以不改善设计的方式应用得墨忒耳定律

时间:2013-09-07 15:07:20

标签: oop coupling law-of-demeter cohesion

假设我们有以下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。 告诉,不要问原则不予保留。因此,德米特定律很满意,但设计仍然不稳定。

问题: (正式)第二个代码段是否真的违反了得墨忒耳法?

注意:问题的目的不是找到替代解决方案,而是确认/反驳解决方案符合得墨忒耳法

1 个答案:

答案 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实例请求所需的一切。