Domanda

Sono un po 'confuso su un paragrafo nel codice completo del libro.

Nella sezione "Classi da evitare", si legge:

"Evitare le classi che prendono il nome verbi Una classe che ha solo il comportamento, ma non ci sono dati non è generalmente in realtà una classe. Considerare trasformando una classe come DatabaseInitialization () o StringBuilder () in una routine su qualche altra classe"

Il mio codice è costituito principalmente da classi verbali senza dati. Ci sono invoicereaders, pricecalculators, messagebuilders ecc Lo faccio per concentrare le classi per un compito ciascuna. Poi aggiungo dipendenze ad altre classi per altre funzionalità.

Se ho capito bene il paragrafo dovrei usare codice come

class Webservice : IInvoiceReader, IArticleReader {
    public IList<Invoice> GetInvoices();
    public IList<Article> GetArticles();
}

anziché

class InvoiceReader : IInvoiceReader {
    public InvoiceReader(IDataProvider dataProvider);
    public IList<Invoice> GetInvoices();
}

class ArticleReader : IArticleReader {
    public ArticleReader(IDataProvider dataProvider);
    public IList<Article> GetArticles();
}

Modifica Grazie per tutte le risposte.

La mia conclusione è che il mio codice attuale è più SRP di OO, ma che soffre anche il "modello di dominio anemico".

Sono sicuro tesi intuizioni mi aiuteranno in futuro.

È stato utile?

Soluzione

I nomi di classe come InvoiceReader, Calcolatore prezzi, MessageBuilder, ArticleReader, InvoiceReader non sono in realtà i nomi dei verbi. Sono davvero nomi di classi "sostantivo agente-sostantivo". Vedi sostantivi agente .

Un nome di classe verbo sarebbe qualcosa di simile Convalida, operano, gestiscono ecc Ovviamente questi sono meglio utilizzati come metodi e sarebbe abbastanza imbarazzante come i nomi delle classi.

Il problema più grande con i nomi di classe "sostantivo agente-sostantivo" è che possono dare molto poco significato da ciò che la classe realmente fa (ad esempio UserManager, DataProcessor ecc). Come risultato, essi sono più probabilità di essere gonfio e di perdere la coesione interna. (Vedi Responsabilità unico principio ).

Quindi la classe WebService con le interfacce IInvoiceReader e IArticleReader è probabilmente la progettazione OO più chiara e significativa.

Questo ti dà la semplice, ovvia sostantivo nome della classe "WebService", insieme a nomi di interfaccia "sostantivo agente-sostantivo" che pubblicizzano in modo chiaro ciò che la classe WebService può fare per i chiamanti.

Si potrebbe forse anche dare più significato alla classe reale anteponendo un altro sostantivo, per esempio PaymentWebService.

Tuttavia le interfacce sono sempre meglio di una singola classe nome di descrivere più precisamente ciò che la classe può fare per i chiamanti. Mentre la classe si fa più complessa, nuove interfacce possono anche essere aggiunti con nomi significativi.

Altri suggerimenti

Ignoro questa "regola", personalmente. Il .NET Framework in sé è pieno di "verbo" classi: TextReader, BinaryWriter, XmlSerializer, CodeGenerator, StringEnumerator, HttpListener, TraceListener, ConfigurationManager, TypeConverter, RoleProvider ... se si pensa che il quadro è mal progettato, quindi con tutti i mezzi, non utilizzare nomi come questi.

L'intento di Steve è comprensibile. Se vi trovate a creare decine e decine di classi solo per svolgere un compito specifico, è probabile un segno di un dominio anemico modello di , in cui gli oggetti che dovrebbe essere in grado di fare queste cose da soli non lo sono. Ma ad un certo punto si deve fare una scelta tra OOP "puro" e il SRP .

Il mio suggerimento sarebbe questo: Se vi trovate a creare una classe "verbo" che agisce su una singola classe "nome", pensa onestamente su se o non la classe "sostantivo" può eseguire l'azione di per sé. Ma non iniziare a creare Dio oggetti o venire con nomi senza senso / fuorvianti per il solo scopo di evitando il verbo di classe.

Non seguire qualche consiglio alla cieca. Queste sono solo linee guida.

Detto questo, I nomi fanno i nomi di classe molto buoni , a patto che modellano oggetti logici. Dal momento che la classe "Persona" è un progetto per tutti "persona" oggetti, definendolo "Persona" è molto utile, perché permette di ragionare in questo modo: "Creerò una Persona dall'input dell'utente, ma prima ho bisogno per confermarla ... "

Si prega di notare l'uso della parola "Evita". Non è eliminare, o sradicare, o bruciare all'inferno se mai li utilizzano.

Ciò che l'autore voleva dire è che se ci si trova con un gruppo di classi di tutti che prendono il nome i verbi e tutto quello che capita di fare è creare staticamente thoses classi, chiamare una funzione e dimenticarsi di loro, probabilmente è un segno che si è separare un po 'le preoccupazioni di classe troppo.

Tuttavia, ci sono situazioni in cui le classi che creano per implementare un'azione è una buona cosa, come quando si dispone di strategie diverse per la stessa azione. Un ottimo esempio è IComparer <>. Tutto ciò che fa è confrontare due cose, ma ci sono diversi modo di confrontare le cose.

Come l'autore ha suggerito, in questi casi, un buon modo per farlo è attraverso la creazione di un'interfaccia e la sua attuazione. IComparer <> viene in mente di nuovo.

Un'altra situazione comune è quando l'azione ha uno stato di pesante, come ad esempio il caricamento dei file. Potrebbe diventare giustificato per incapsulare lo stato in una classe.

In sostanza ciò che il libro sta dicendo è che il design OO è sull'estrazione gli oggetti (i sostantivi) e indichi le operazioni (i verbi) che si verificano su e tra questi oggetti.

I nomi diventano gli oggetti, i verbi diventano i metodi che operano su questi oggetti.

L'idea è che il

  

più stretti i modelli di programma della reali   problema del mondo, meglio il programma   saranno.

In pratica la cosa utile con un oggetto è che può rappresentare uno stato particolare. Poi si può avere diverse istanze di questa classe ciascuna azienda uno stato diverso per rappresentare alcuni aspetti del problema.

Nel caso della classe InvoiceReader

  • si sono solo andando a essere la creazione di un'istanza
  • l'unica condizione che rappresenta è quella di contenere un dataProvider
  • contiene un solo metodo

non c'è alcun vantaggio per collocandolo in un oggetto.

La dichiarazione Una classe che ha solo il comportamento, ma non ci sono dati non è generalmente in realtà una classe. è semplicemente sbagliato.

Estrazione comportamento in una classe a parte è una cosa buona e comune da fare in refactoring. Può avere stato, ma anche non ha bisogno di avere uno. È necessario disporre di interfacce pulite, e la loro attuazione in ogni caso a trovare necessario.

Inoltre, le classi apolidi sono grandi per i calcoli è necessario solo per un breve periodo di tempo. Li un'istanza (o, richiedere una fabbrica di qualche tipo per farli), fare i calcoli necessari, e poi gettarli a spazzatura. Si può avere la "versione" in uso nel proprio comportamento a disposizione sempre e ovunque.

Di solito trovo che diverse implementazioni di un'interfaccia hanno una certa posizione (inserita nel costruttore, per esempio), ma a volte il tipo di classe in grado di determinare completamente il suo comportamento.

Ad esempio:

public interface IExporter
{
    /// <summary>
    /// Transforms the specified export data into a text stream.
    /// </summary>
    /// <param name="exportData">The export data.</param>
    /// <param name="outputFile">The output file.</param>
    void Transform(IExportData exportData, string outputFile);
}

può essere implementato come

class TabDelimitedExporter : IExporter { ... }
class CsvExporter : IExporter { ... }
class ExcelExporter : IExporter { ... }

Per implementare l'esportazione da IExportData (qualunque essa sia) in un file CSV, probabilmente non è necessario alcun Stato a tutti. ExcelExporter, d'altra parte, potrebbe avere varie proprietà per le opzioni di esportazione, ma potrebbe anche essere senza stato.

[Edit]

Muoversi GetInvoices e GetArticles nella classe WebService significa che legherà la loro attuazione al tipo WebService. Averli in classi separate vi permetterà di avere implementazioni diverse per entrambe le fatture e articoli. Nel complesso, sembra meglio averli separati.

Focus meno sul nome. La regola relativa al nome è solo un indicatore regola empirica per una pratica povero. Il punto importante è questo:

  

Una classe che ha solo il comportamento, ma non ci sono dati non è generalmente in realtà una classe

Nel tuo caso, sembra come se le vostre classi hanno sia i dati e il comportamento, e che possono anche essere chiamato "fattura" e "articolo".

Dipende. Un sacco di classi di esistere il nome di Lettura e Scrittura verbi perché le classi anche creare, mantenere, e rappresentano un collegamento alla sorgente dati che stanno leggendo o scrivendo da. Se i corsi che stanno facendo, probabilmente è meglio tenerli separati.

Se gli oggetti Reader semplicemente contengono l'analisi logica, quindi trasformando le classi in metodi di utilità è la strada da percorrere. Mi piacerebbe andare con un nome più descrittivo di Webservice però.

Credo che il libro suggerisce un design simile al seguente:

class Article : IIArticleReader
{
    // Article data...

    public IList<Article> GetArticles(); 
}

Ecco un introito classico su 'verbo vs sostantivo' in OO:

http: // steve-Yegge .blogspot.com / 2006/03 / esecuzione-in-regno-di-nouns.html

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top