2012-03-09 48 views
7

問題「告訴,不要問」在多個域對象

如何執行涉及多個對象的功能,當我堅持"Tell, Don't Ask"原則。

示例 - 生成報告

我有以下對象(說明目的):

車,馬,兔

有這些對象之間沒有任何關係,但我確實希望根據這些對象生成報告:

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

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

該方法的問題在於它必須從每個對象中「拉出」數據,這違反了「Tell,Do not Ask」規則。我寧願保持隱藏在每個對象的內部,並讓他們爲我生成一個報告:

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

......但後來我得到3頁的報告。此外,我不認爲兔子應該知道如何生成我需要的每個報告(HTML,JMS,XML,JSON ....)。

最後,同時生成我可能要對多個項目進行切換的報告:

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

+1&fav用於鏈接和問題。 – knownasilya 2012-12-06 21:54:16

回答

8

報告應保持創建自身的能力。

在這種情況下,每個IReportable對象應執行void UpdateReport(Report aReport)

當調用Report.CreateReport(List<Reportable> aList),它遍歷列表,並在自己的執行UpdateReport每個對象調用:

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

截至CreateReport末,報告對象應該產生自己的結果。

+1

訪客及雙重派遣規則! – 2012-03-14 21:45:21

+0

要清楚,'Report'必須有'AddCar'和'AddHorse'實現嗎?我假設這些方法的名稱只是爲了舉例,但它們非常具有誤導性。實際上,我浪費了10分鐘的時間才明白,這些方法與Car和Horse類型本身沒有關係o_O – 2015-05-18 03:40:54

6

「告訴別人不要」規則的目標是幫助您識別應該與給定對象相關的責任最終落在其外部(壞事)的情況。
我們可以在您的案件中看到什麼責任?我看到的是:

1)知道如何格式的報表(以XML,ASCII,HTML等)
2)知道什麼去上報告

第一個顯然不與域對象屬於(汽車,馬等)。 2)去哪裏?人們可以建議域對象,但是如果系統中有多個不同的報告,那麼最終會給您的對象添加有關不同報告細節的知識,這些細節看起來和聞起來都不好。更不用說它會違反單一責任原則:作爲兔子是一回事,但知道兔子信息的哪些部分應該繼續報告X與報告Y是另一回事。因此,我會設計封裝數據內容的類,這些數據內容將在特定類型的報告上進行(並可能執行必要的計算)。我不會擔心他們閱讀兔子,馬或汽車的數據成員。這個類實現的責任是「爲特定類型的報告收集數據」,你有意識地決定應該位於域對象之外。

1

我不知道到底該模式的名稱(訪問者,生成器,...):

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

這種方式,您可以有相同的域對象的多種表示,沒有違反「告訴別問「原則。