2012-03-09 16 views
7

Pytanie„Tell, nie pytaj” na wiele kategorii obiektów

Jak mogę stosować się do zasady "Tell, Don't Ask" podczas wykonywania funkcji udziałem wielu obiektów.

Przykład - Generowanie raportu

Mam następujące obiekty (jedynie w celach poglądowych):

Wóz, Koń, Królik

nie ma żadnego związku między tymi obiektami , ale chcę wygenerować raport na podstawie tych obiektów:

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

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

Problem z tą metodą polega na tym, że musi "wyciągnąć" dane z każdego obiektu, co jest niezgodne z zasadą "Powiedz, nie pytaj". Wolałbym zachować wnętrze każdego obiektu ukryte, i mieć je wygenerować raport dla mnie:

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

... ale potem dostać 3 raportów cząstkowych. Ponadto, nie sądzę, że królik powinien wiedzieć, jak wygenerować każdy raport, którego potrzebuję (HTML, JMS, XML, JSON ...).

Wreszcie, podczas generowania raportu może chcę, aby przełączyć się na wielu elementów:

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

+1 i fav dla linku i pytania. – knownasilya

Odpowiedz

8

Raport powinien zachować zdolność do tworzenia jego jaźń.

W tym przypadku każdy obiekt IReportable powinien zaimplementować void UpdateReport(Report aReport).

Kiedy Report.CreateReport(List<Reportable> aList) jest wywoływana, to iteracje poprzez listy i każdy obiekt we własnym realizacji UpdateReport wywołuje:

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

Pod koniec CreateReport, obiekt raport powinien produkować swój własny wynik.

+1

Reguła odwiedzin i podwójnej wysyłki! –

+0

, aby było jasne, 'Raport' musi mieć zaimplementowane' AddCar' i 'AddHorse'? Zakładam, że te nazwy metod są brane tylko na przykład, ale są bardzo mylące i. właściwie zmarnowałem 10 minut, żeby zrozumieć, że te metody nie mają nic wspólnego z typami samochodów i koni samych o_O –

6

Celem zasady "Nie pytaj" jest pomoc w określeniu sytuacji, w których odpowiedzialność, która powinna spoczywać na danym obiekcie, zostaje zaimplementowana poza nim (złe rzeczy).
Jakie obowiązki widzimy w Twojej sprawie? Co ja widzę to:

1) wiedząc, jak sformatować raport (w formacie XML, ASCII, html, etc)
2) wiedząc, co się dzieje, na którym raport

Pierwszy z nich oczywiście nie należą do obiektu domeny (Samochód, jazda itp.). Gdzie powinien iść 2)? Ktoś mógłby zasugerować obiekt domeny, ale jeśli w twoim systemie istnieje wiele różnych raportów, to obciążasz obiekty wiedzą o różnych szczegółach raportu, które wyglądałyby i pachniały źle. Nie wspominając o tym, że naruszałoby to zasadę odpowiedzialności pojedynczej: bycie Królikiem to jedno, ale wiedząc, które części informacji Rabbit powinny znaleźć się w raporcie X, a raport Y to zupełnie co innego. W ten sposób zaprojektowałbym klasy, które obejmowałyby zawartość danych, która trafia na określony typ raportu (i ewentualnie wykonują niezbędne obliczenia). Nie martwiłbym się o to, że będą czytać członków danych Królika, Konia lub Samochodu.Odpowiedzialność, którą ta klasa implementuje, polega na "zbieraniu danych dla określonego typu raportu", o których świadomie zdecydowałeś, że powinny znajdować się poza obiektem domeny.

1

Nie wiem dokładnie nazwę tego wzorca'S (Visitor, Builder, ...):

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 { 
    ... 
} 

W ten sposób można mieć wiele reprezentacje tego samego obiektu domeny, nie naruszono „Powiedz nie zapytaj "zasada.