Design: metodo dell'oggetto contro il metodo della classe separata che accetta Object come parametro?

14

Ad esempio, è meglio fare:

Pdf pdf = new Pdf();
pdf.Print();

o

Pdf pdf = new Pdf();
PdfPrinter printer = new PdfPrinter();
printer.Print(pdf);

Un altro esempio:

Country m = new Country("Mexico");
double ratio = m.GetDebtToGDPRatio();

o

Country m = new Country("Mexico");
Country us = new Country("US");
DebtStatistics ds = new DebtStatistics();
double usRatio = ds.GetDebtToGDPRatio(us);
double mRatio = ds.GetDebtToGDPRatio(m);    

La mia preoccupazione nell'ultimo esempio è che ci sono potenzialmente infinite statistiche (ma diciamo anche solo 10) che potresti voler sapere su un paese; appartengono tutti all'oggetto country?

per es.

Country m = new Country("Mexico");
double ratio = m.GetGDPToMedianIncomeRatio();

Questi sono rapporti semplici, ma lascia che le statistiche siano abbastanza complicate da giustificare un metodo.

Dove si trova quella linea tra le operazioni che sono intrinseche a un oggetto e le operazioni che possono essere eseguite su un oggetto ma non ne fanno parte?

    
posta User 20.05.2011 - 00:00
fonte

2 risposte

16

Prendendo i tuoi esempi PDF come punto di partenza, diamo un'occhiata a questo.

link

Il principio di responsabilità unica suggerisce che un oggetto dovrebbe avere un solo obiettivo. Tienilo a mente.

link

Il principio Separation of Concerns ci dice che le classi non dovrebbero avere funzioni sovrapposte.

Quando guardi questi due, suggeriscono che la logica dovrebbe andare in una classe solo se ha senso, solo se tale classe è responsabile di farlo.

Ora, nel tuo esempio PDF, la domanda è: chi è il responsabile della stampa? Cosa ha senso?

Primo snippet di codice:

Pdf pdf = new Pdf();
pdf.Print();

Questo non va bene. Un documento PDF non si stampa da solo. Viene stampato da ... ta da! .. una stampante. Quindi il secondo snippet di codice è molto meglio:

Pdf pdf = new Pdf();
PdfPrinter printer = new PdfPrinter();
printer.Print(pdf);

Questo ha senso. Una stampante Pdf stampa un documento pdf. Meglio ancora, una stampante non dovrebbe essere una stampante PDF o una stampante fotografica. Dovrebbe essere solo una stampante in grado di stampare cose inviate al meglio delle sue capacità.

Pdf pdf = new Pdf();
Printer printer = new Printer();
printer.Print(pdf);

Quindi è semplice. Metti i metodi dove hanno senso. Ovviamente, non è sempre così semplice. Prendi le statistiche del tuo paese, ad esempio:

Country m = new Country("Mexico");
double ratio = m.GetDebtToGDPRatio();

La tua preoccupazione è che potrebbe esserci un n numero di statistiche e che non dovrebbero essere in una classe Paese. Questo è vero. Tuttavia, se il tuo modello richiede solo determinate statistiche, questo esempio di modellazione potrebbe effettivamente andare bene.

In questo caso, si potrebbe dire abbastanza logicamente che un paese dovrebbe essere in grado di calcolare le proprie statistiche, specifiche per il proprio modello e per i requisiti disponibili.

E qui sta la cosa: quali sono le tue esigenze? Le tue esigenze guideranno il tuo modo di modellare il mondo, il contesto in cui questi requisiti devono essere soddisfatti.

Se in effetti hai un numero di statistiche variabile / variabile, allora il tuo secondo esempio ha più senso:

Country m = new Country("Mexico");
DebtStatistics ds = new DebtStatistics();
double usRatio = ds.GetDebtToGDPRatio(m);

Meglio ancora, avere una superclasse o un'interfaccia astratta chiamata Statistiche che accetta un paese come parametro:

interface StatisticsCalculator // or a pure abstract class if doing C++
{
   double getStatistics(Country country); // or a pure virtual function if in C++
}

classe DebtToGDPRatioStatisticsCalculator implementa StatisticsCalculator ....

classe InfantMortalityStatisticsCalculator implementa StatisticsCalculator ...

E così via e così via. Il che porta a quanto segue: generalizzazione, delega, astrazione. La raccolta statistica ottiene delegata a istanze specifiche che generalizza una astrazione specifica (un'API di raccolta statistiche).

Non so se questo risponde alla tua domanda al 100%. Dopotutto, non abbiamo modelli infallibili fondati su leggi inviolabili (come fanno gli EE). Tutto quello che puoi fare è mettere le cose se fossero sensate. E questa è una decisione ingegneristica che devi prendere. La cosa migliore da fare è conoscere i principi OO (e buoni principi di modellazione del software in generale).

    
risposta data 20.05.2011 - 00:31
fonte
4

Penso che nessuno dei due sia decisamente migliore dell'altro. L'uso di pdf.Print () è più stretto, ma avere una classe PdfPrinter potrebbe essere migliore se:

  • Devi gestire le istanze delle stampanti
  • Ci sono una vasta gamma di opzioni e azioni che spazzerebbero via la complessità pdf.Print (...) (ad esempio cancellazione della stampa, formattazione extra, ecc.)

Altrimenti non mi farei impiccare.

    
risposta data 20.05.2011 - 00:32
fonte