2012-03-09 47 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 { 
    ... 
} 

这种方式,您可以有相同的域对象的多种表示,没有违反“告诉别问“原则。