4

デメテルの法則に従いたい。「2つのドット」を検索するコードを調べていると、このタイプのコンテキストで委任の責任を設定する価値があるかどうかを自問自答しています。

から

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

あなたの考えは何ですか?

4

2 に答える 2

2

あなたの例はデメテルの法則を破っていません。ユーザーはアクティビティの属性であり、ユーザーのパブリックAPIメソッドにアクセスしているため、元の実装でエラーが発生することはありません。

デメテルの法則の目標は、オブジェクトのカプセル化を壊さないようにすることです。あなたの「2つの点」のアプローチは、アイデアをいくぶん単純化しすぎています。実際には、オブジェクトがどのように相互作用しているかを調べ、他のオブジェクトの属性や関係を深く読んでいないことを確認する必要があります。たとえば、次の場合はルールに違反します。

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

これは、アドレスがユーザーのビジネスであり、ユーザーのAPIを介してアドレスへのアクセスを適切にカプセル化する必要があるという事実によるものです。ユーザーのクライアントとして、ユーザー属性のAPIに直接アクセスすることはできません。

繰り返しになりますが、あなたの例では、ユーザーAPIを直接使用していますが、これは問題なく、デメテルの法則に違反していません。そうは言っても、私は一般的なルールに従うのが良いと思いました。図のようにオブジェクトのカプセル化を壊さないようにすると、通常、コードの変更と保守が容易になり、クラスのリファクタリングが容易になります。

于 2011-05-24T01:07:13.033 に答える
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なるように思われます。そして、デメテルの法則の要点(私はそれをガイドラインとしてもっと考えるのが好きです..)は、クラスの外で多くのコードを書き直すことなく、内部で好きなことをできるべきであるということです。あなたのモジュールはあまり役に立ちません-あなたがの内部をいじるとき、あなたはまだそのコードを書き直すことができます。UserUserDelegatorUser

しかし、それが私だったとしたら、に簡単な変更を加えるために多くのコードを書き直していることに気付いていない限り、これを気にすることすらないと思いますUser。たぶんそれは、私がLinuxカーネルのコーディングスタイルに慣れているからです。これは、定期的にデメテルの法則に違反しています。

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

3つのオブジェクトが離れています:)そして私はコードが書かれた場合にもっと読みやすくなるかどうかわかりません:

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

ですから、私はすべて適度にガイドラインに従うことに賛成です-あなたの変更が実際にクリーンでより保守しやすいコードにつながるのか、それともルールに従うためにルールに従っているだけなのかを自問してください。

于 2011-05-23T23:19:02.837 に答える