Diseño: Método de objeto vs método de clase separado que toma el objeto como parámetro.

14

Por ejemplo, es mejor hacerlo:

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

o:

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

Otro ejemplo:

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);    

En el último ejemplo, mi preocupación es que hay estadísticas potencialmente infinitas (pero digamos que solo 10) es posible que desee saber sobre un país; ¿Todos ellos pertenecen al objeto país?

por ejemplo

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

Estos son índices simples, pero supongamos que las estadísticas son lo suficientemente complicadas como para justificar un método.

¿Dónde está esa línea entre las operaciones que son intrínsecas a un objeto frente a las operaciones que se pueden realizar en un objeto pero que no son parte de él?

    
pregunta User 20.05.2011 - 00:00

2 respuestas

16

Tomando tus ejemplos de PDF como punto de partida, veamos esto.

enlace

El principio de responsabilidad única sugiere que un objeto debe tener uno y solo un objetivo. Ten esto en cuenta.

enlace

El principio de separación de inquietudes nos dice que las clases no deben tener funciones superpuestas.

Cuando observas estos dos, sugieren que la lógica debe ir en una clase solo si tiene sentido, solo si esa clase es responsable de hacerlo.

Ahora, en su ejemplo de PDF, la pregunta es, ¿quién es el responsable de imprimir? ¿Qué tiene sentido?

Primer fragmento de código:

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

Esto no es bueno. Un documento PDF no se imprime solo. Se imprime por ... ta da! .. una impresora. Así que tu segundo fragmento de código es mucho mejor:

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

Esto tiene sentido. Una impresora Pdf imprime un documento pdf. Mejor aún, una impresora no debería ser una impresora PDF o una impresora fotográfica. Simplemente debe ser una impresora capaz de imprimir todo lo que se le envíe lo mejor que pueda.

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

Así que eso es simple. Poner métodos donde tengan sentido. Obviamente, no siempre es así de simple. Tome las estadísticas de su país, por ejemplo:

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

Su preocupación es que podría haber n número de estadísticas, y que no deberían estar en una clase de País. Eso es verdad. Sin embargo, si su modelo solo solicita estadísticas particulares, este ejemplo de modelado podría estar bien.

En este caso, podría decir lógicamente que un país debería poder calcular sus propias estadísticas, específicas para su modelo y los requisitos disponibles.

Y ahí está la cosa: ¿cuáles son sus requisitos? Sus requisitos impulsarán la forma en que modela el mundo, el contexto en el que se deben cumplir estos requisitos.

Si efectivamente tiene un número de estadísticas de multitudes / variables, entonces su segundo ejemplo tiene más sentido:

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

Mejor aún, tenga una superclase o interfaz abstracta llamada Estadísticas que toma a un país como parámetro:

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

la clase DebtToGDPRatioStatisticsCalculator implementa StatisticsCalculator ....

la clase InfantMortalityStatisticsCalculator implementa StatisticsCalculator ...

Y así sucesivamente y así sucesivamente. Lo que lleva a lo siguiente: generalización, delegación, abstracción. La recopilación de estadísticas obtiene delegado a instancias específicas que generalizan una abstracción específica (una API de recopilación de estadísticas).

No sé si esto responde a tu pregunta al 100%. Después de todo, no tenemos modelos infalibles basados en leyes inviolables (como las de EE). Todo lo que puedes hacer es poner las cosas donde tienen sentido. Y esa es una decisión de ingeniería que debes tomar. Lo mejor que puedes hacer es familiarizarte con los principios de OO (y los buenos principios de modelado de software en general).

    
respondido por el luis.espinal 20.05.2011 - 00:31
4

Creo que ninguno es definitivamente mejor que el otro. El uso de pdf.Print () es más estricto, pero tener una clase PdfPrinter podría ser mejor si:

  • Es necesario administrar las instancias de las impresoras
  • Hay una amplia gama de opciones y acciones que podrían eliminar la complejidad del pdf.Impresión (...) (por ejemplo, cancelación de impresión, formato adicional, etc.)

De lo contrario, no me engancharía.

    
respondido por el Kevin Hsu 20.05.2011 - 00:32

Lea otras preguntas en las etiquetas