得墨忒耳定律 - 你走多远?

时间:2011-05-23 22:58:12

标签: ruby-on-rails law-of-demeter

我想遵循得墨忒耳法则。当我通过我的代码搜索“两个点”时,我发现自己在询问是否真的值得在此类背景下设置委托责任:

class Activity
  def increment_user_points!
    self.user.increment_points!(points, true)
  end
end

module UserDelegator
  def user_increment_points!(points, increment_credits=false)
    self.user.increment_points!(points, increment_credits)
  end
end

class Activity
  include UserDelegator

  def increment_user_points!
    user_increment_points!(points, true)
  end
end

你有什么想法?

2 个答案:

答案 0 :(得分:2)

你的例子并没有打破德米特定律。用户是活动的属性,您正在访问用户的公共API方法,因此您不会错误地使用原始实现。

Demeter法则的目标是避免破坏对象封装。你的“两点”方法有点过于简单化了。实际上,您应该检查对象的交互方式,并确保您不会读取其他对象的属性或关系。例如,如果以下内容违反了规则:

def update_user_address
  @user.address.set(new_address)
end

这可能是因为地址是用户的业务,它应该通过用户的API适当地封装对它的访问。作为用户的客户,我们永远不应该直接访问用户属性的API。

同样,在您的示例中,您直接使用用户API,这很好,并且没有违反Demeter法。所有这一切,我发现一般规则是一个很好的遵循。如果您避免破坏对象封装,您的代码通常会更容易更改和维护,并且类将更容易重构。

答案 1 :(得分:1)

我实际上希望TO看起来更像这样:

class User
  def increment_points!(points, increment_credits)
    @points+=points if increment_credits
    @points-=points unless increment_credits
  end
end

class Activity
  def increment_user_points!
    @user.increment_points!(points, true)
  end
end

将模块创建为include似乎会创建更多复杂性。 Demeter法则的全部要点(我更喜欢将其视为指南......)是你应该能够对User的内部做任何你喜欢的事情,而不必重写很多代码课外。你的UserDelegator模块没什么用处 - 当你摆弄User的内部时,你仍然可以重新编写代码。

但是,如果是我,我认为我甚至不打扰这个,除非你发现自己重写代码的很多来对User进行简单的更改。也许这只是因为我已经习惯了Linux内核编码风格,它会定期违反Demeter的规律:

static inline int need_reval_dot(struct dentry *dentry)
{
    if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE)))
        return 0;

    if (likely(!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)))
        return 0;

    return 1;
}

三个对象:)我不确定如果写的代码会更清晰:

need_reval_dot(dentry) {
    if(likely(!dentry_need_reval_dot(dentry))
        return 0;
}

dentry_need_reval_dot(dentry) {
    return superblock_need_reval_dot(dentry->d_sb);
}

superblock_need_reval_dot(sb) {
    return fs_type_need_reval_dot(sb->s_type);
}

fs_type_need_reval_dot(s_type) {
    return fs_flags_need_reval_dot(s_type->fs_flags);
}

fs_flags_need_reval_dot(fs_flags) {
    return fs_flags & FS_REVAL_DOT;
}

因此,我赞成遵循适度的指导原则 - 问问自己,您的修改是否真正导致更清晰,更易于维护的代码,或者是否只是为了遵守规则而遵循规则。