クリーンコードでは、「書式設定」の章の「垂直距離」セクションで保護された変数を避けることを推奨しています。
密接に関連する概念は、垂直方向に互いに近づける必要があります。明らかに、このルールは別々のファイルに属する概念には機能しません。ただし、非常に適切な理由がない限り、密接に関連する概念を別のファイルに分割しないでください。実際、これは保護された変数を避けるべき理由の1つです。
理由は何ですか?
クリーンコードでは、「書式設定」の章の「垂直距離」セクションで保護された変数を避けることを推奨しています。
密接に関連する概念は、垂直方向に互いに近づける必要があります。明らかに、このルールは別々のファイルに属する概念には機能しません。ただし、非常に適切な理由がない限り、密接に関連する概念を別のファイルに分割しないでください。実際、これは保護された変数を避けるべき理由の1つです。
理由は何ですか?
回答:
保護された変数は次の理由で避ける必要があります。
しかし、ご覧のとおり、これらはすべて「傾向」です。保護されたメンバーが最もエレガントなソリューションである場合があります。そして、保護された機能はこれらの問題の少ない傾向があります。しかし、それらを慎重に扱わせる多くのことがあります。そのような注意を必要とするものは何でも、人々は間違いを犯し、プログラミングの世界ではバグと設計上の問題を意味します。
グローバル化を避ける理由は、まさに小規模ですが、それはまさに同じ理由です。それは、変数が読み取られている、またはさらに悪いことに、書き込まれているすべての場所を見つけるのが難しく、使用法の一貫性を保つのが難しいからです。派生クラスの1つの明白な場所で記述され、基本クラスの1つの明白な場所で読み取られるなど、使用が制限されている場合、保護された変数によりコードがより明確で簡潔になります。複数のファイル全体で変数を自由に読み書きしたい場合は、それをカプセル化することをお勧めします。
私は本を読んでいませんが、ボブおじさんの意図を突き刺すことができます。
protected
何かを置くと、クラスがそれを継承できることを意味します。ただし、メンバー変数は、それらが含まれるクラスに属すると想定されています。これは基本的なカプセル化の一部です。protected
メンバー変数を設定すると、派生クラスが基本クラスの実装の詳細にアクセスできるようになるため、カプセル化が解除されます。public
通常のクラスで変数を作成するときに発生する問題と同じです。
問題を修正するには、次のように変数を保護されたプロパティにカプセル化できます。
protected string Name
{
get { return name; }
private set { name = value; }
}
これによりname
、基本クラスの実装の詳細を公開することなく、コンストラクター引数を使用して派生クラスから安全に設定できます。
protected
ありpublic
ます。BaseType
パブリックメンバーを公開する場合DerivedType
、BaseType
参照を受け取り、そのメンバーの使用を予期するコードにインスタンスが渡される可能性があるため、すべての派生型は同じメンバーが同じように機能する必要があることを意味します。場合はこれとは対照的に、BaseType
公開されるprotected
メンバを、その後DerivedType
にそのメンバーにアクセスすることを期待することがありbase
ますが、base
何もすることはできません、他のよりBaseType
。
ボブおじさんの議論は、主に距離の1つです。クラスにとって重要な概念がある場合は、そのファイル内のクラスと概念をまとめてください。ディスク上の2つのファイルに分割されていません。
保護されたメンバー変数は2つの場所に散在しており、ちょっと魔法のように見えます。この変数を参照していますが、ここでは定義されていません...どこで定義されていますか?そして、狩りが始まります。protected
彼の主張は完全に避ける方が良い。
今、私は規則が常に手紙に従う必要があるとは思わない(例えば:あなたは使わないprotected
)。彼が得ているものの精神を見てください...関連するものを1つのファイルにまとめてください-それを行うためにプログラミング技術と機能を使用してください。分析しすぎて、これに関する詳細に巻き込まれないようにすることをお勧めします。
すでに非常に良い答えがここにあります。ただし、追加することが1つあります。
ほとんどの最新のOO言語では、各クラスを独自のファイルに配置するのが良い習慣です(Javaでは必要です)(多くの場合、2つのファイルがあるC ++については気にしないでください)。
したがって、基本クラスの保護された変数にアクセスする派生クラスの関数を、ソースコード内で変数定義に「垂直に」維持することは事実上不可能です。しかし、理想的には、保護された変数は内部使用を目的としているため、そこに保持する必要があります。
基本的な考え方は、保護されていると宣言された「フィールド」(インスタンスレベルの変数)は、おそらく必要以上に見えやすく、必要以上に「保護されていない」ということです。C / C ++ / Java / C#には「同じアセンブリ内の子クラスからのみアクセス可能」に相当するアクセス修飾子がないため、アセンブリ内のフィールドにアクセスできる独自の子を定義する機能が付与されますが、他のアセンブリで作成された子に同じアクセスを許可しない。C#には内部修飾子と保護修飾子がありますが、それらを組み合わせると、アクセスは「内部および保護」ではなく「内部または保護」になります。したがって、保護されたフィールドは、あなたがその子供を書いたのか、他の誰かが書いたのかに関係なく、どの子供からもアクセスできます。したがって、保護はハッカーにとって開かれた扉です。
また、フィールドの定義によると、フィールドの変更に固有の検証はほとんどありません。C#では、1つの読み取り専用を作成できます。これにより、値型は事実上定数になり、参照型は再初期化できません(ただし、非常に変更可能)が、それだけです。そのため、保護されている場合でも、(信頼できない)子はこのフィールドにアクセスし、無効な値に設定して、オブジェクトの状態を一貫性のないもの(回避すべきもの)にすることができます。
フィールドを操作するために受け入れられている方法は、フィールドをプライベートにし、プロパティ、および/またはゲッターとセッターメソッドでアクセスすることです。クラスのすべてのコンシューマーが値を必要とする場合、ゲッターを(少なくとも)公開します。子供だけが必要な場合は、ゲッターを保護してください。
質問に答える別のアプローチは、自問することです。子メソッドのコードに、状態データを直接変更する機能が必要なのはなぜですか?それはそのコードについて何を言っていますか?それがその顔の「垂直距離」引数です。親の状態を直接変更する必要があるコードが子にある場合、そのコードは最初に親に属している必要がありますか?
興味深い議論です。
率直に言って、優れたツールはこれらの「垂直」問題の多くを軽減できます。実際、私の意見では、「ファイル」という概念は実際にはソフトウェア開発を妨げるものです-Light Tableプロジェクトが取り組んでいるもの(http://www.chris-granger.com/2012/04/12/light-テーブル--- a-new-ide-concept /)。
ファイルを写真から外すと、保護されたスコープがより魅力的になります。保護された概念は、継承がクラスの元の概念を単に拡張するSmallTalkのような言語で最も明確になります。親クラスが実行したすべてを実行し、すべてを実行する必要があります。
私の意見では、クラス階層は可能な限り浅く、ほとんどの拡張機能は構成に基づいている必要があります。そのようなモデルでは、プライベート変数が保護されない理由は見当たりません。拡張クラスが親クラスのすべての動作を含む拡張機能を表す必要がある場合(それが必要であり、したがってプライベートメソッドが本質的に悪いと考える)、拡張クラスがそのようなデータのストレージも表すべきではないのはなぜですか?
別の言い方をすれば、プライベート変数が保護されている変数よりも適していると感じる場合、継承はそもそも問題の解決策ではありません。
そこにあるように、これは理由の1つにすぎません。つまり、論理的にリンクされたコードは、物理的にリンクされたエンティティ(ファイル、パッケージなど)内に配置する必要があります。小規模では、これは、UIを表示するクラスを含むパッケージ内にDBクエリを作成するクラスを配置しない理由と同じです。
ただし、保護された変数が推奨されない主な理由は、カプセル化を破壊する傾向があるためです。変数とメソッドの可視性はできるだけ制限する必要があります。詳細については、Joshua BlochのEffective Javaの Item 13-「クラスとメンバーのアクセシビリティを最小限に抑える」を参照してください。
ただし、この広告のすべてをギルドラインとしてとるべきではありません。保護された変数が非常に悪い場合、そもそも言語内に配置されていません。保護フィールドimhoの合理的な場所は、テストフレームワークからの基本クラス内です(統合テストクラスはそれを拡張します)。
はい、私は(私が思い出すように)本がすべての非プライベート変数についても避けるべきものとして議論していることを考えると、それはいくぶん奇妙であることに同意します。
protected修飾子の問題は、メンバーがサブクラスに公開されるだけでなく、パッケージ全体からも見えるようになることだと思います。ボブおじさんがここで例外を取っているのは、この二重の側面だと思います。もちろん、常に保護されたメソッド、したがって保護された変数の修飾を回避することはできません。
もっと面白いアプローチはすべてを公開することだと思います。それは小さなクラスを持つことを強制し、その結果、垂直距離メトリック全体がやや意味のないものになります。