假设我们有以下Boy
类,它试图通过分析她的日程表来安排Girl
的日期(例如Java):
public class Boy {
public boolean tryArrangeDate(Girl girl, Date time) {
boolean success = true;
for (GirlRoutine routine : girl.getSchedule()) {
if (routine.happensAt(time)) {
success = false;
break;
}
}
return success;
}
}
由于Boy.tryArrangeDate()
调用, routine.happensAt()
方法明显违反了得墨忒耳法。解决此问题的方法之一是将计划分析直接移至Girl
,并避免依赖GirlRoutine
。在这种情况下,这可能是最好的决定之一。 Boy
课程的RFC将会减少。
但是假设我们选择了不同的方向来解决违反Demeter法的行为并以这种方式更改代码:
public class Boy {
public boolean tryArrangeDate(Girl girl, Date time) {
return isFree(girl.getSchedule(), time);
}
private boolean isFree(List<GirlRoutine> schedule, Date time) {
boolean free = true;
for (GirlRoutine routine : schedule) {
if (happensAt(routine, time)) {
free = false;
break;
}
}
return free;
}
private boolean happensAt(GirlRoutine routine, Date time) {
return routine.happensAt(time);
}
}
添加了两个私有方法,只需将调用委托给Girl
及其日程安排/例程。
单独采用的每种方法似乎都不违反得墨忒耳法则(为简单起见,我们将从集合中检索项目视为原始的无方法调用操作)。但总体而言,我们没有减少此类的RFC,没有提高凝聚力,实际上增加了WMC。 告诉,不要问原则不予保留。因此,德米特定律很满意,但设计仍然不稳定。
问题: (正式)第二个代码段是否真的违反了得墨忒耳法?
注意:问题的目的不是找到替代解决方案,而是确认/反驳解决方案符合得墨忒耳法
答案 0 :(得分:0)
<强>更新强>
既然你只是问第二个是否仍然违反了得墨忒耳法则,那么是的,我认为确实如此。无论你如何重构 tryArrangeDate
,它都不会改变它从GirlRoutine
调用方法的事实。当得墨忒耳法则提到“对象的任何方法”时,我认为它指的是其他对象可以访问的方法,这些方法暴露于“外部世界”。第二个代码段中的私有方法只是tryArrangeDate
的辅助方法。
<强>最初强>
Girl
类就其自身的GirlRoutine
而言是“专家”。您必须尽可能地将其隐藏起来。请记住tell, don't ask的原则。
也许你可以这样做:
Response response = girl.askOut(boy, date);
不要像Girl实例询问Boy实例那样阅读它;我遵循的经验法则(大部分时间)是你调用方法的对象是方法所代表的动作的直接对象。在这种情况下,askOut
的直接对象是Girl实例。
Response
类可以获得有关它如何运行的信息,或者它可以是简单的类似:
enum Response { ACCEPTED, REJECTED }
这样,Girl
实例具有接受或拒绝Boy
实例请求所需的一切。