È un odore di codice se si crea frequentemente un oggetto solo per chiamare un metodo su di esso


14

Ho ereditato una base di codice in cui c'è molto codice che va in questo modo:

SomeDataAdapter sda = new SomeDataAdapter();
sda.UpdateData(DataTable updateData);

E poi sda non viene mai più utilizzato.

È un odore di codice che indica che quei metodi dovrebbero effettivamente essere metodi di classe statici?


Queste classi implementano delle interfacce?
Reactgular

7
Il giorno successivo al refactoring ai metodi statici sarà il giorno in cui si desidera eseguire test unitari con una versione derisa dell'adattatore dati.
Mike

22
@ Mike: Perché mai dovresti deridere un metodo statico? Mi sto stancando tremendamente di questo fallace argomento secondo cui i metodi statici non sono testabili. Se i tuoi metodi statici mantengono lo stato o creano effetti collaterali, è colpa tua , non colpa della tua metodologia di test.
Robert Harvey,

9
Secondo me, è un odore del linguaggio che mostra la debolezza dell'analisi "tutto deve essere una classe".
Ben

7
@RobertHarvey: potrebbe essere necessario deridere un metodo statico per lo stesso motivo per cui si deride qualsiasi altro metodo: è troppo costoso da chiamare durante il test unitario.
Kevin Cline,

Risposte:


1

Lo considererei un odore di architettura in quanto UpdateData probabilmente dovrebbe appartenere a una classe di "servizio".

Dove i dati sono una Apple. Dove AppleAdapter è un servizio / classe di business intelligence. Dove AppleService è un riferimento Singleton a un AppleAdapter che esiste al di fuori del metodo corrente.

private static volatile AppleAdapter _appleService = null;
private static object _appleServiceLock = new object();
private AppleAdapter AppleService
{
    get
    {
        if (_appleService == null)
        {
            lock (_appleServiceLock)
            {
                if (_appleService == null)
                    _appleService = new AppleAdapter();
            }
        }
        return _appleService;
    }
}

public SomeAppleRelatedMethod(Apple apple)
{
    AppleService.UpdateData(apple);
}

Non penso che ciò che stai facendo sia necessariamente sbagliato, ma se SomeDataAdapter rappresenta davvero un qualche tipo di servizio aziendale senza stato, allora un singleton sarebbe la migliore pratica per questo. Spero possa aiutare! L'esempio fornito è un modo fantasioso per garantire l'assenza di contese di _appleService se si verifica che entrambi sono nulli e vi si accede esattamente allo stesso tempo da due o più thread.

Sai cosa? Se SomeDataAdapter è un IDbDataAdapter ADO (che quasi sicuramente lo è), ignora l'intera risposta!

: P

Non ho il permesso di aggiungere un commento alla domanda originale, ma se potessi specificare dove esiste questo codice.

Se questo codice rappresenta un'implementazione personalizzata di un IDbDataAdapter e UpdateData sta creando un IDbConnection, un IDbCommand e lo sta cablando tutto dietro le quinte, allora no non prenderei in considerazione che un odore di codice perché ora stiamo parlando di stream e altro cose che devono essere eliminate quando abbiamo finito di usarle.


12
Aiuto! Sto affogando nei modelli software.
Robert Harvey,

4
... o iniettato come dipendenza. ;)
Rob

12
Fare casini con i singoli e il doppio controllo per ottenere qualcosa di equivalente a una semplice funzione / procedura è un odore di codice molto più grande per me!
Ben

3

Penso che questo problema sia ancora più profondo di così. Anche se lo si converte in un metodo statico, si ottiene il codice in cui si chiama un singolo metodo statico ovunque. Che secondo me è l'odore del codice in sé. Potrebbe indicare che ti stai perdendo qualche astrazione importante. Forse vuoi creare un codice che eseguirà alcune operazioni di pre e post elaborazione e ti permetta di cambiare ciò che accade nel mezzo. Che pre e post-elaborazione conterranno gli inviti comuni mentre l'intervallo dipenderà da un'implementazione concreta.


Sono d'accordo che c'è un problema molto più profondo. Sto cercando di migliorarlo in modo incrementale senza una riprogettazione architettonica completa, ma sembra che quello che stavo pensando non sia un buon modo per farlo.
Shane Wealti,

1

Tipo. Di solito significa che vuoi passare una funzione in giro e la tua lingua preferita non ti permetterà. È un po 'goffo e inelegante, ma se sei bloccato in una lingua senza funzioni di prima classe, non c'è molto che puoi fare.

Se nessuno di questi oggetti viene passato come argomento ad altre funzioni, è possibile trasformarli in metodi statici e nulla cambierebbe.


Potrebbe anche significare che vuoi che il metodo statico restituisca una versione modificata (o una copia modificata) di un oggetto che gli stai passando.
Robert Harvey,

2
"se sei bloccato in una lingua senza funzioni di prima classe": non vi è alcuna differenza tra un oggetto con un solo metodo e una funzione di prima classe (o chiusura di prima classe): sono solo due viste diverse della stessa cosa.
Giorgio,

4
@Giorgio Teoricamente, no. In pratica, se la vostra lingua non ha almeno uno zucchero sintassi per esso, è la differenza tra fn x => x + 1e new Function<Integer, Integer>() { public Integer eval(Integer x) { return x + 1; }};o voi stessi limitando a poche funzioni hard-coded e stretto-utili.
Doval,

Perché non potrebbe fn x => x + 1essere lo zucchero sintattico per new Function<Integer, Integer>() { public Integer eval(Integer x) { return x + 1; }}? Ok, forse vuoi dire se uno è bloccato in una lingua senza questo tipo di zucchero sintattico.
Giorgio,

@Giorgio Dovrai chiedere a Oracle. (Certo, finalmente sta cambiando con Java 8). Tieni presente che avresti bisogno di più zucchero di sintassi che solo per essere davvero utile - vorresti anche essere in grado di passare metodi pre-dichiarati per nome. Currying sarebbe anche utile. Ad un certo punto devi chiederti se vale la pena avere tutti quegli hack invece di considerare le funzioni come i primi cittadini. Ma ora sto diventando fuori tema.
Doval,

0

Se il mantenimento dello stato rende una determinata classe più utile, funzionale ... riutilizzabile, allora no. Per qualche ragione viene in mente il modello di progettazione del comando ; quella ragione non è certo il desiderio di far annegare Robert Harvey.


0

Definisci "frequentemente". Con quale frequenza istanzia l'oggetto? Molto - probabilmente no?

Probabilmente ci sono problemi più grandi di cui preoccuparsi nel tuo sistema. Andare statico comunicherà più chiaramente al programmatore che lo stato interno dell'oggetto non sta cambiando - fantastico.

Se però lo stato è incasinato e devi iniziare a rendere statiche altre cose per rendere statica la prima cosa, allora devi chiedere quali parti devono essere statiche e quali no.

, è un odore di codice, solo piccolo.


0

Rendilo un metodo statico e vai avanti. Non c'è niente di sbagliato nei metodi statici. Una volta che emerge un modello d'uso, puoi preoccuparti di astrarre il modello.


0

L'odore qui è che questo è un codice procedurale racchiuso (minimamente) in oggetti.

Ci deve essere un motivo per cui si desidera eseguire tale operazione sulla tabella dei dati, ma piuttosto che modellare quell'operazione con altre operazioni correlate che condividono una semantica (cioè hanno un significato comune), l'autore ha appena avviato una nuova procedura all'interno di una nuova classe e lo chiamò.

In un linguaggio funzionale, è così che faresti le cose;) ma nel paradigma OO, vorresti modellare qualche astrazione che includeva quell'operazione. Quindi useresti le tecniche OO per dare forma a quel modello e fornire una serie di operazioni correlate che preservano un po 'di semantica.

Quindi l'odore principale qui è che l'autore sta usando le classi, probabilmente perché il compilatore lo richiede, senza organizzare le operazioni in un modello concettuale.

A proposito, fai attenzione ogni volta che vedi il programma modellato invece dello spazio problematico . È un segno che il design potrebbe beneficiare di più pensiero. In altre parole, fai attenzione alle classi che sono tutte "xAdaptor" e "xHandler" e "xUtility", e di solito legate a un modello di dominio anemico . Significa che qualcuno sta semplicemente raggruppando il codice per comodità, invece di modellare effettivamente i concetti che vogliono implementare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.