web-dev-qa-db-ja.com

保護されたプロパティは悪ですか?

コードの紹介部分:

class BaseClass
{
    protected Foo MyFoo { get; }
}

class ChildClass : BaseClass
{
    void SomeMethod()
    {
        MyFoo.DoStuff();
        //Here, I have no idea that MyFoo is not defined in this class,
        //but rather in the base class.
    }
}

問題/議論は、MyFooが定義されている場所を手動で確認または確認する必要があることです。そして、基本クラスと子クラスの2つのプライベートフィールドを使用するほうがよいでしょう。

私たちの場合、ほとんどの場合、これらのプロパティは 依存性注入 から取得され、両方のクラスのコンストラクタで使用できます。そのため、基本クラスから継承するのではなく、コンストラクターからプライベートプロパティにマッピングするだけで簡単にできます。

私が見逃している良い習慣はありますか?そこでの経験は?

根底にある質問:保護されたプロパティは単に悪い習慣であり、代わりに常にプライベートフィールドに行くべきですか?

単体テストのときにこれは私に反しますか?

これはクリーン/アンクリーンコードと見なされますか?

1
Gil Sand

サブクラス(およびそのコンストラクター)でプロパティを複製することは、実際にはより良い代替手段ではないと思います。実際の読み取り/書き込みプロパティの場合、同じ機能を実現することすらできません。読み取り専用の注入プロパティの場合(ある種のサービスの場合)、定義されている場所はそれほど重要ではありません。さらに、あなたのIDEはそれを簡単に示すことができます。

基本的に、それを見る方法はこれです:

  • プロテクトフィールドは、メソッドと同様に、サブクラス化のためのクラスAPIの一部です。
  • 変更可能なデータを実際に含む保護フィールドでは、コードが確実に理解できなくなる可能性がありますが、サブクラスでオーバーライドされてスーパークラスで呼び出されたときに保護メソッドが含まれる可能性があります。
  • ここでの問題は保護されたフィールドまたはメソッドではなく、問題はサブクラス化です。慎重かつ慎重に使用する必要があります。
  • 私がその場で作成した経験則:スーパークラスは非常に小さくシンプルであるか、サブクラスである必要があります。そして、深い継承階層は悪いです。
21

myFooが定義されている場所を知っているか、手動で確認する必要があります

しかし、それは保護されたプロパティにどのように特有ですか?同じことがメソッドにも当てはまり、実際にはanyパブリックメンバーです。継承の大きな理由の1つは、すべての具象型で同じことを繰り返す必要がないようにすることです。したがって、基本動作と基本ストレージ定義を含む共通の基本タイプを持つことができます。

保護されているプロパティまたはフィールドは、これが可能性が高いサブクラスに関連する内部実装の詳細であることを通知します。ある意味で、これは実際には、各レベルで完全に接続されていないプライベートプロパティを持っているだけではありません。

そして、コンパイラーはそれがどこに定義され、どのようにアクセスできるかをすでに知っています。また、優れた編集者は設計時にそれを伝えるので、「手動でチェック」する必要は実際にはありません。さらに、型を継承するときは、そのインターフェイスに慣れていることを期待しているので、使用できる保護されたメンバーがあることを知っています

私たちの場合、これらのプロパティは依存関係の注入に由来します

これは私の意見かもしれませんが、依存関係には常にプロパティではなくreadonlyfieldsを使用します。

そのため、それらをそのコンストラクターからプライベートプロパティにマップするだけで本当に簡単です。

確かに、型階層の各レベルにプライベートフィールドを持つことができます。しかし、それはそれらを追跡するために必要なメモリ使用量も複製します。そして、これらがコンストラクタに注入された不変の依存関係であるという事実をしばらく無視すると、基本クラスはそのサブクラスの値をchangeできません問題が発生する可能性もあります。

保護されたプロパティは単に悪い習慣であり、代わりに常にプライベートフィールドに行くべきですか?

ここには2つの質問があります: プロパティvs.フィールド 、およびprotectedprivate。後者に答えるには、カプセル化の意味で意味のあるものを使用します。基本タイプに、サブクラスが使用できる実際の内部APIがある場合、それらを保護する必要があります。ただし、万が一に備えて依存関係を保護するだけではいけません

12
poke

保護されたプロパティは悪ですか?

いいえ。保護されているプロパティはsmellyですが、evilはありません。つまり、「私はこれを正しくモデリングしていますか?」プロパティは、モデルのパブリックサーフェス領域の一部と見なされ、フィールドは、モデルのプライベートな実装の詳細と見なされます。 「保護された」は単に「この階層のプライベートな実装の詳細」を意味するため、保護されたプロパティではなく保護されたフィールドが必要です。

とはいえ、保護されたプロパティは間違っているではありません。これらは、デザインについてもう少し難しく考える必要があるという兆候にすぎません。

ここで、MyFooがこのクラスではなく、基本クラスで定義されていることはわかりません。

もちろん、あなたはそれを知っています。クラスのソースコードを読むと、そのようなプロパティがないことがはっきりとわかります。また、「定義に移動」して、プロパティのソースコードに移動できます。

問題/議論は、MyFooが定義されている場所を手動で確認または確認する必要があることです。

いいえ、必要ありません。なぜそれがどこに定義されているのかを知る必要があると思いますか?

そして、基本クラスと子クラスの2つのプライベートフィールドを使用するほうがよいでしょう。

いいえ、まったく同意しません。基本クラスで保護されたフィールドを使用するほうがよいでしょう。

保護されたプロパティは単に悪い習慣であり、代わりに常にプライベートフィールドに行くべきですか?

多くの保護されたプロパティを作成していることに気付いた場合、それらが実際に保護されたフィールドとしてより適切にモデル化されているかどうかを自問します。覚えておいてくださいプロパティはモデル化されたもののプロパティをモデル化する必要がありますCarクラスを記述している場合、そのプロパティは車のプロパティである必要があります。 車のプロパティ車の階層の実装の詳細の両方は何ですか?私はそれらの両方であるとは何も考えられないので、保護されたプロパティがあるべきではないかもしれません。

6
Eric Lippert