ささいな保護されたゲッターは過剰に露骨ですか?


8

私が以前に本当に考えたことがないもの(AS3構文):

private var m_obj:Object;
protected function get obj():Object
{
    return m_obj;
}

private var m_str:String;
protected function get str():String
{
    return m_str;
}

少なくともサブクラスはm_objまたはm_strを設定できません(ただし、m_objを変更することはできます)。

私の質問:これは単なる露骨なやりすぎですか?


このプログラマーの質問: 単純にパブリックプロパティにするのではなく、クラスプロパティのゲッター/セッターをいつまたはなぜ使用する必要があるのでしょうか。 重複として提案されています。

その質問は、パブリックプロパティとプライベートプロパティのみを扱い、プロパティをゲッターとセッターでラップする必要があるかどうかという点で異なります。私の質問では、保護された変数と、継承するクラスがそれらの変数とどのように相互作用するかに焦点を当ててます。

したがって、代替実装は次のようになります。

protected var m_obj:Object; //more accessible than a private variable with a protected getter
protected var m_str:String; //more accessible than a private variable with a protected getter

簡単な保護されたゲッターを使用して、サブクラスが変数に書き込むのをブロックし、他のすべてのアクセスを許可することを話しているので、私の質問も同様です。
AS3のような言語では、参照自体が変更されていない限り、可変オブジェクト変数に変更を加えることもできます。


2
自問してみてください; 答えが「はい」の場合、サブクラスが任意の値に設定できるのは危険ですか、それは過剰ではありません
ラチェットフリーク

1
質問を編集して、代わりに何をしていないことについて話しているかをより明確にしました。
Panzercrisis 2013年

回答:


6

これは単なる露骨なやりすぎですか?

しばしばそうですが、そうでない場合もあります。

m_obj既知の良好な状態を維持することで、リスコフ置換の原則を保護し、コードの回復力と品質を向上させることができます。時には継承者を信頼してその振る舞いを尊重できることもあれば、そうでないこともあります(使用パターンまたはそれが実装するコントラクトの繊細さのため)。このコード/質問は、「クリーンなコードが保護された変数の回避を提案する理由の理由のいくつかにつまずきますが


nullまたは別のインスタンスに設定することを除いて、サブクラスがm_objに対してほぼすべてのことを実行できる場合、それは価値がありますか?
Panzercrisis 2013年

@Panzercrisis-言語によって異なります。メモリ管理されていない言語では、それをnullまたは他の何かに設定することは大きな問題です。
Telastyn 2013年

13

平凡な保護されたゲッターには、公開された変数よりも少なくとも2つの実用的な利点があります。

  • デバッグには、「おかしな値がプログラムに入る」ときにトリガーされる条件付きブレークポイントを配置するのに最適な場所です。値に直接アクセスする場合、同じコントロールを取得することははるかに困難です。

  • オブジェクトをモックするために、このメソッドを使用して子孫をテストしている場合。

ゲッターを使用するコストは事実上ゼロであるため、ゲッターを使用しないという本当の理由はありません。ある?


ありがとうございました。質問は明確にするために編集されています。
Panzercrisis 2013年

私の答えはゲッターのpublicor protected属性を参照していません!:-)
Michael Le BarbierGrünewald2013年

ああ、ごめんなさい。
Panzercrisis 2013年

4
コストは膨大なコードにあります。コストはそれほど大きくありませんが、ゼロより大きくなります。確かに、ゲッターは取るに足らないものですが、誰かがクラスで作業するたびに渡される必要があります。そして、それらは間違っている可能性があります。get x() ... { return _y; } 誰もそれをタイプすることはありませんが、間違ったカットアンドペーストが原因で発生する可能性があります。
kevin cline 2013年

3
ただし、これは異なるコスト間のトレードオフです。そして、私の経験では、サブクラスが親クラスを微妙な方法で侵害するバグを追跡するコストは、ゲッターとセッターを維持するコストに比べて莫大です。
Julia Hayward

7

ゲッターを使用してもフィールドアクセスを使用しても、経験豊富なレビューアーはデザインの問題を発見し、オブジェクトが動作ではなくデータを公開していると不満を言うでしょう。

継承の目的は親(LSP)の動作を調整/調整できるようにすることであり、親データを無差別にいじることを正当化しないため、「保護された」にアピールしても役に立たないことに注意してください。通りバートランド・メイヤーがそれを置きます、

オープンクローズの原則も継承の再定義も、設計上の欠陥に対処する方法ではありません...(このルールの唯一の潜在的な例外は、自由に変更できない欠陥のあるソフトウェアの場合です。)

「ゲッターは悪だ」という推論は、get明示的にスペルするか、フィールドアクセスの背後でマスクするかに関係なく適用されます。

参照この記事この記事アラン・ホルブによると...

これらのメソッドはクラスの実装方法に関する情報を公開し、その結果、コードの保守が困難になるため、絶対に必要な場合を除いて、アクセサメソッド(ゲッターおよびセッター)を使用しないでください。get / setメソッドが避けられない場合もありますが、経験豊富なOO設計者は、おそらく現在コード内にあるアクセサーの99%をそれほど問題なく取り除くことができます。

ゲッター/セッターメソッドは、コーダーが手続き的に考えていたため、コード内でうまく機能することがよくあります。その手続き型の考え方から抜け出す最善の方法は、明確に定義された責任を持つオブジェクト間の会話の観点から考えることです...

問題について真剣に懸念している場合、最初に考慮すべきことは、不適切な方法を選択する無益なマインドゲームをプレイするのではなく、ゲッターと非プライベートフィールドアクセスの両方を取り除くコードの再設計です。

もう一度強調する価値があります。問題のあるデザインを「保護された」スモークスクリーンの後ろに隠しても、問題は解消されません-継承はそのようなトリックを正当化しません。質問を言い換えると、継承クラスがそれらの変数対話しないように(ゲッターやフィールドアクセスを介さずに)設計するよう努めてください。教えてください、尋ねないでください

手続き型コードは情報を取得してから決定を行います。オブジェクト指向コードはオブジェクトに物事を行うように伝えます。

情報を取得する方法を決定するために時間と労力を費やして、これを完全に回避することを推奨する古典的な原則に反して、今ではそれは私にとって露骨なやりすぎのように聞こえます。


私たちは同じ学校の出身です。「基本クラスが正しく機能しないので、データをいじくるにはどうすればよい」という質問は、「基本クラスを機能させて、いじる必要がないようにするにはどうすればよい」内部状態とは?」ゲッターを実装することはめったにありません。セッターを実装することはほとんどありません。私のクラスのメソッドは、「Tell Do n't Ask」の流れのコマンドです。時々、私は主な仕事の責任の1つが、怠惰なプログラマーや無知なプログラマーによって公開された実装の詳細を隠すことによってバグを修正することだと感じています。
ダッシュトムバン

1

不変クラスの実装の場合、内部変数を保護すると、設定したコントラクトが壊れます。その場合、保護されたゲッターは過剰ではなく、必要ありません(変数へのポインターではなく、変数のコピーを返す必要があります) )。

可変クラスでは、内部変数への直接アクセスを許可するよりも、ゲッター/セッターを優先します。これにより、クライアントコードを壊すことを恐れずに、内部変数の処理方法を自由に変更できます。たとえば、次のようなJavaクラスがあるとします。

public abstract class SomeClass {
    protected int[] someVariable;

    // Rest of implementation
}

SomeClass次に、拡張するクライアントクラスは、に直接アクセスしsomeVariable、適切に見えるように操作します。これで、これらのクラスがsomeVariable許容可能な状態のままにならない場合、あらゆる種類の問題が発生する可能性があります。さらに、後続のリリースで配列の代わりにSomeClassを使用するList<Integers>ように定義を変更すると、既存のコードベースとの互換性が失わSomeClassれ、intsのリストではなくsの内部配列を持つことが期待されますint

この場合、保護されたゲッターを使用すると、事前に確立された契約を破ることなくこの変更を行うことができます。

public abstract class SomeClass {
    List<Integer> someVariable;

    protected int[] getSomeVariable () {
        // Return int[] version of someVariable
    }

    // Rest of implementation
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.