2012-03-09 11 views
7

Pregunta"Tell, no preguntar" sobre varios objetos de dominio

¿Cómo se adhieren al principio "Tell, Don't Ask" al realizar una función de la participación de múltiples objetos.

Ejemplo - Generación de un informe

tengo los siguientes objetos (título ilustrativo):

coche, caballo, conejo

no hay ninguna relación entre estos objetos , pero sí quiero generar un informe basado en estos objetos:

createHtmlReport(Car car, Horse horse, Rabbit rabbit){ 
    Report report = new Report() 

    report.setSomeField(car.getSerialNumber()) 
    report.setAnotherField(horse.getNumberOfLegs()) 
    // ...etc  
} 

El problema con este método es que tiene que "extraer" datos de cada objeto, lo que infringe la regla "Decir, no preguntar". Yo prefiero mantener el interior de cada objeto oculto, y hacer que se genere un informe para mí:

car.createHtmlReport() 
horse.createHtmlReport() 
rabbit.createHtmlReport() 

... pero entonces obtener 3 informes parciales. Además, no creo que un Conejo deba saber cómo generar cada informe que necesito (HTML, JMS, XML, JSON ...).

Por último, mientras que la generación del informe es posible que quiera cambiar en varios elementos:

if (car.getWheels() == 4 || horse.getLegs() == 4) 
    // do something 
+0

+1 y favorito para el enlace y la pregunta. – knownasilya

Respuesta

8

El informe debe mantener la capacidad de crear su propia.

En este caso, cada objeto IReportable debe implementar void UpdateReport(Report aReport).

Cuando se invoca Report.CreateReport(List<Reportable> aList), se itera por la lista y cada objeto en su propia implementación de UpdateReport invoca:

aReport.AddCar(serialNumber) 
aReport.AddHorse(horseName) 

Al final de CreateReport, el objeto de informe debe producir su propio resultado.

+1

regla de visitante y doble despacho! –

+0

para ser claros, 'Informe' debe tener' AddCar' y 'AddHorse' implementados? supongo que estos nombres de métodos se toman solo por ejemplo, pero son muy engañosos y. de hecho, perdí como 10 minutos solo para entender que estos métodos no tienen nada que ver con los tipos de autos y caballos en sí mismos o_O –

6

El objetivo de la regla "Decir no preguntar" es ayudarlo a identificar situaciones en las que la responsabilidad que debe recaer sobre el objeto dado termina implementándose fuera de ella (lo malo).
¿Qué responsabilidades podemos ver en su caso? Lo que veo es:

1) saber cómo formatear el informe (en XML, ASCII, HTML, etc)
2) saber lo que pasa en el cual informan

En primer lugar, obviamente, no pertenece con el objeto de dominio (Coche, Caballo etc.). ¿A dónde debería ir el 2)? Se podría sugerir el objeto de dominio, pero si hay múltiples informes diferentes en su sistema, terminará por sobrecargar sus objetos con el conocimiento de los diferentes detalles del informe que se verán y huelen mal. Sin mencionar que violaría el Principio de Responsabilidad Individual: ser un Conejo es una cosa, pero saber a qué parte de la información de Conejo debería ir en el informe X frente a reportar Y es otra muy distinta. Por lo tanto, diseñaría clases que encapsularan los contenidos de datos que van en un tipo específico de informe (y posiblemente realicen los cálculos necesarios). No me preocuparía que leyeran los datos de los miembros de Rabbit, Horse o Car.La responsabilidad que implementa esta clase es "recopilar los datos para un tipo específico de informe" que conscientemente ha decidido que debe estar fuera del objeto de dominio.

1

No sé exactamente el nombre de este patrón (Visitante, constructor, ...):

public interface HorseView { 
    void showNumberOfLegs(int number); 
} 

public interface CarView { 
    void showNumberOfWheels(int number); 
    void showSerialNumber(String serialNumber); 
} 

public class Horse { 

    void show(HorseView view) { 
     view.showNumberOfLegs(this.numberOfLegs); 
    } 

} 

public class Car { 

    void show(CarView view) { 
     view.showNumberOfWheels(this.numberOfWheels); 
     view.showSerialNumber(this.serialNumber); 
    } 

} 

public class HtmlReport implements HorseView, CarView { 

    public void showNumberOfLegs(int number) { 
     ... 
    } 

    public void showNumberOfWheels(int number) { 
     ... 
    } 

    public void showSerialNumber(String serialNumber) { 
     ... 
    } 

} 

public XmlModel implements HorseView, CarView { 
    ... 
} 

public JsonModel implements HorseView, CarView { 
    ... 
} 

De esta manera se pueden tener varias representaciones del mismo objeto de dominio, no violar "Dile que no hacer pregunta "principio".

Cuestiones relacionadas