我想遵循得墨忒耳法则。当我通过我的代码搜索“两个点”时,我发现自己在询问是否真的值得在此类背景下设置委托责任:
这
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
你有什么想法?
答案 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;
}
因此,我赞成遵循适度的指导原则 - 问问自己,您的修改是否真正导致更清晰,更易于维护的代码,或者是否只是为了遵守规则而遵循规则。