得墨忒尔定律——你能走多远?

发布于 2024-11-09 21:28:45 字数 526 浏览 2 评论 0原文

我想遵循德墨忒尔法则。当我在代码中搜索“两个点”时,我发现自己问自己是否真的值得在这种类型的上下文中设置委托职责:

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

您的想法是什么?

I want to follow the Law of Demeter. As I am going through my code searching for the "two dots", I find myself asking if it's really worth setting up the delegation responsibilities in this type of context:

FROM

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

TO

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

What are your thoughts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

樱娆 2024-11-16 21:28:45

你的例子并没有违反德米特法则。用户是 Activity 的一个属性,并且您正在访问用户的公共 API 方法,因此原始实现不会出现错误。

德米特定律的目标是避免破坏对象封装。你的“两点”方法有点过于简单化了这个想法。实际上,您应该检查对象是如何交互的,并确保您没有过多地了解其他对象的属性或关系。例如,如果以下情况违反规则:

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

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

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

Your example is not breaking the Law of Demeter. The user is an attribute of the activity and you are accessing a public API method on the user, so you are not in error with the original implementation.

The goal of the Law of Demeter is to avoid breaking object encapsulation. Your "two dots" approach is somewhat of an oversimplification of the idea. In reality, you should examine how your objects are interacting and ensure that you are not reading too far into the attributes or relationships of other objects. For instance, if the following would be a violation of the rule:

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

This would be due to the fact that the address is the business of the user, and it should encapsulate access to it appropriately through the user's API. As a client of the user, we should never directly have access to the API's of the users attributes.

Again, in your example, you are using the users API directly, which is fine and is not violating Demeters Law. All that said, I have found the general rule to be a good one to follow. Your code will generally be easier to change and maintain and classes will be easier to refactor if you avoid breaking object encapsulation as shown.

独木成林 2024-11-16 21:28:45

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

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 的模块似乎会产生更多复杂性。德墨忒尔法则的全部要点(我更喜欢将其视为指南......)是,您应该能够对用户的内部进行任何您喜欢的操作,而不必在类外重写大量代码。您的 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;
}

所以我所有人都赞成适度遵循准则——问问自己,您的修改是否实际上会导致更干净、更易于维护的代码,或者是否只是为了遵循规则而遵循规则。

I'd actually expect TO to look more like this:

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

Creating a module to include would seem to create more complexity. And the whole point of the Law of Demeter (I like to think of it more as a guideline..) is that you ought to be able to do whatever you like to User's internals without having to rewrite much code outside the class. Your UserDelegator module doesn't help much -- you still get to re-write that code when you fiddle with User's internals.

But if it were me, I don't think I'd even bother with this, unless you're finding yourself rewriting a lot of code to make simple changes to User. Maybe that's just because I'm used to the Linux kernel coding style, which breaks the law of Demeter on a regular basis:

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;
}

Three objects away :) and I'm not sure the code would be more legible if written:

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;
}

So I'm all in favor of following guidelines in moderation -- ask yourself if your modifications actually lead to cleaner, more maintainable code, or if it is just following a rule for the sake of following rules.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文