Le classi concrete evitano di chiamare altre classi concrete, ad eccezione degli oggetti dati?

4

Nell'appendice A a The Art of Unit Testing , Roy Osherove, parlando dei modi per scrivere codice testabile dall'inizio, dice

An abstract class shouldn't call concrete classes, and concerete classes shouldn't call concrete classes either, unless they're data objects (objects holding data, with no behavior). (259)

La prima metà della frase è semplicemente D ependency Inversion di SOLID. La seconda metà sembra piuttosto estrema per me. Ciò significa che ogni volta che scriverò una classe che non è una semplice struttura dati, che è la maggior parte delle classi, dovrei prima scrivere un'interfaccia o una classe astratta, giusto? Vale veramente la pena andare così lontano nel definire le classi astratte come interfacce? Qualcuno può spiegare perché in modo più dettagliato, o rifiutarlo nonostante i suoi vantaggi per la testabilità?

    
posta Kazark 14.09.2012 - 19:30
fonte

5 risposte

11

That means that every time I'm going to write a class that isn't a simple data structure, which is most classes, I should write an interface or abstract class first, right?

Sì.

Is it really worthwhile to go that far in defining abstract classes an interfaces?

No, ma dovresti errare verso più interfacce che meno.

Can anyone explain why in more detail, or refute it in spite of its benefit for testability?

Direi che è bene usare direttamente le classi concrete fintanto che quelle classi concrete non fanno parte dell'interfaccia che il consumatore sta implementando / fornendo. Non appena sono parte dell'interfaccia pubblica piuttosto che dell'implementazione di un modulo, devono essere astratti o devono essere abbastanza stabili da essere sicuro che il codice non stia andando avere bisogno di cambiare o essere polimorfico.

    
risposta data 14.09.2012 - 19:35
fonte
4

Non penso che voglia dire che dovresti scrivere una classe astratta per ogni classe, necessariamente. Penso che voglia dire che dovrebbe esserci un modo per sostituire una classe di test per la classe concreta. Questo potrebbe essere fatto tramite un contenitore DI, per esempio.

Di solito vale la pena andare così lontano perché di solito stai scrivendo un test che sostituisce una classe di test per la classe concreta, ma se non hai bisogno del test, non devi preoccuparti.

    
risposta data 14.09.2012 - 19:38
fonte
3

IMHO un approccio più pragmatico non è pensare in "classi" quando si disaccoppiano parti del sistema per una migliore testabilità, ma pensare in "componenti" - unità funzionali più grandi con un compito ben definito che può essere composto da uno o più lezioni. Se un componente ha bisogno del servizio di un altro, non dovrebbe usarlo direttamente, ma solo tramite un'interfaccia. L'aspetto di questa interfaccia può essere molto dipendente dal componente, può essere utilizzare la definizione della lingua di un interface nel linguaggio di programmazione, può essere solo una funzione o una richiamata, può utilizzare flussi o qualche tipo di "oggetti dati" ".

Per la mia esperienza, è anche una buona idea per testabilità progettare le interfacce dei componenti in modo da poter fornire tutti gli input e gli output in memoria. Ad esempio, supponiamo di avere il componente A che utilizza gli oggetti del tuo database come input e output, e il componente B, che si basa sull'output di A, e utilizza anche il database. Quindi fornisci un modo in cui A produce gli oggetti dati solo in memoria e un modo in cui B può accettare anche quegli oggetti da A in memoria, senza alcuna interazione con un database. Ciò rende la scrittura di test automatici per A e B molto più semplice (e i test vengono eseguiti molto più velocemente).

    
risposta data 15.09.2012 - 10:39
fonte
2

Vale solo la pena andare a questi estremi se bevi il test unitario / TDD Kool-Aid. Per rendere più semplice il collaudo delle unità, è necessario seguire determinati progetti. Alcuni di questi progetti vanno contro i tradizionali concetti di progettazione OO. Sta a te decidere se i potenziali guadagni derivanti dai test unitari pesino sul costo di dover fare alcune considerazioni di progettazione scadenti. I test unitari sono lontani dal proiettile d'argento, molti cercano di farli apparire, ma è l'attuale moda del design.

    
risposta data 14.09.2012 - 19:42
fonte
0

La Gang of Four implica anche che sia definita una classe astratta o un'interfaccia per ogni classe concreta. Subito dopo aver introdotto il principio Programma in un'interfaccia, non un'implementazione -e quindi, come conseguenza diretta di esso - si dice (18):

Don't declare variables to be instance of particular concrete classes.

Questo non è possibile a meno che per ogni classe concreta che viene istanziata esista una classe o un'interfaccia astratta.

Pertanto, sembrerebbe che questo sia il caso in cui la progettazione di testabilità promuove ciò che era già considerato una buona progettazione orientata agli oggetti. Dato che Design Patterns è uscito quasi due decenni fa, direi che il concorso della Gang of Four con Osherove è un segno che tutto quel test unitario non lo ha fatto ammalare nella testa. Piuttosto, sta semplicemente promuovendo un buon design.

Design Patterns è uno dei libri più rispettati nel design orientato agli oggetti, anche adesso. Quindi, come con altri principi di programmazione, non vi è alcun motivo per aderire al consiglio di Osherove con un legalismo che perde il sito di altri aspetti del buon design come KISS, il suo consiglio ovviamente si colloca in una tradizione di pensiero rispettato in materia di oggetti design.

    
risposta data 26.10.2012 - 00:51
fonte

Leggi altre domande sui tag