ゲッターとセッターはいつ正当化されるのか


175

ゲッターとセッターは、適切なオブジェクト指向ではないとしばしば批判されます。一方、私が見たほとんどのオブジェクト指向コードには、広範なゲッターとセッターがあります。

ゲッターとセッターはいつ正当化されますか?それらの使用を避けようとしていますか?それらは一般的に使い古されていますか?

お気に入りの言語にプロパティがある場合(私の場合)、そのようなものもこの質問のゲッターおよびセッターと見なされます。オブジェクト指向の方法論の観点からは同じです。より良い構文を持っています。

Getter / Setter Criticismの情報源(コメントを見やすくするためにコメントから引用したものもあります):

批判を簡単に述べると、ゲッターとセッターを使用すると、オブジェクトの外部からオブジェクトの内部状態を操作できます。これはカプセル化に違反します。オブジェクト自体のみがその内部状態に注意する必要があります。

そして、コードの手続きバージョンの例。

struct Fridge
{
    int cheese;
}

void go_shopping(Fridge fridge)
{
     fridge.cheese += 5;
}

コードのミューテーターバージョン:

class Fridge
{
     int cheese;

     void set_cheese(int _cheese) { cheese = _cheese; }
     int get_cheese() { return cheese; }
 }

void go_shopping(Fridge fridge)
{
     fridge.set_cheese(fridge.get_cheese() + 5);        
}

ゲッターとセッターは、適切なカプセル化を行うことなく、コードをより複雑にしました。内部状態は他のオブジェクトからアクセス可能であるため、これらのゲッターとセッターを追加することで多くを得ることはありません。

この問題は、以前にStack Overflowで説明されています。


21
Getters and setters are often criticized as being not proper OO-引用してください。
ロバートハーヴェイ


45
@ジョブ、なぜコードがあるのですか?真剣に考えれば、それは良い質問であり、聖戦の嫌なものです。
ピーターターナー

2
@Winston Ewert: "...問題は、クラス内のデータにアクセスする必要があるかどうかです"。そのため、パブリックメンバー変数の代わりにゲッターとセッターを使用します。
ジョルジオ

2
@Winston Ewert:ゲッター/セッターの不在がこの問題をどのように解決するかわかりません。すべてのデータにアクセスする方法があるはずです。データのどの部分がコードのどの部分にアクセスできるかを決定するのは、優れた設計のタスクです。悪いデザイナーの場合、ゲッターとセッターの有無にかかわらず、彼または彼女はそのようになります。ちょうど私の2セント。
ジョルジオ

回答:


162

ゲッターとセッターを持つこと自体はカプセル化を壊しません。カプセル化を解除するのは、データメンバー(java lingoのすべてのフィールド)にゲッターとセッターを自動的に追加することです。これは、すべてのデータメンバーをパブリックにするよりも優れていますが、ほんの少しの距離です。

カプセル化のポイントは、オブジェクトの外部からオブジェクトの状態を知ることも変更することもできないことではなく、それを行うための合理的なポリシーを持っていることです。

  • 一部のデータメンバーは、オブジェクトの内部に完全に存在する場合があり、ゲッターもセッターも持たない必要があります。

  • 一部のデータメンバーは読み取り専用である必要があるため、ゲッターは必要ですがセッターは必要ない場合があります。

  • 一部のデータメンバーは、互いに一貫性を保つ必要がある場合があります。そのような場合は、それぞれにセッターを提供するのではなく、値を一貫してチェックできるように、それらを同時に設定する単一の方法を提供します。

  • 一部のデータメンバーは、一定の量だけ増分または減分するなど、特定の方法でのみ変更する必要がある場合があります。この場合、セッターではなくincrement()and / or decrement()メソッドを提供します。

  • しかし、実際には読み取り/書き込みが必要な場合があり、ゲッターとセッターの両方を持っています。

の例を考えてみましょうclass Person。人に名前、社会保障番号、年齢があるとします。人々が名前や社会保障番号を変更することを許可しないとしましょう。ただし、その人の年齢は毎年1ずつ増やす必要があります。この場合、名前とSSNを指定された値に初期化し、年齢を0に初期化するコンストラクターを提供incrementAge()します。また、年齢を1増やすメソッドを提供します。 3つすべてのゲッター。この場合、セッターは必要ありません。

この設計では、オブジェクトの状態をクラスの外部から検査できるようにし、クラスの外部から変更できるようにします。ただし、状態を任意に変更することはできません。ポリシーがあります。これは、名前とSSNをまったく変更できないこと、および年齢を一度に1年ずつ増やすことができることを効果的に示しています。

今、人も給料を持っているとしましょう。そして、人々は自由に仕事を変えることができます。つまり、給与も変わります。この状況をモデル化するには、setSalary()方法を提供する以外に方法はありません!この場合、給与を自由に変更できるようにすることは、完全に合理的なポリシーです。

ところで、あなたの例では、私はクラス与えるだろうと代わりの方法を、と。その後、カプセル化がまだあります。FridgeputCheese()takeCheese()get_cheese()set_cheese()


public class Fridge {
  private List objects;
  private Date warranty;

  /** How the warranty is stored internally is a detail. */
  public Fridge( Date warranty ) {
    // The Fridge can set its internal warranty, but it is not re-exposed.
    setWarranty( warranty );
  }

  /** Doesn't expose how the fridge knows it is empty. */
  public boolean isEmpty() {
    return getObjects().isEmpty();
  }

  /** When the fridge has no more room... */
  public boolean isFull() {
  }

  /** Answers whether the given object will fit. */
  public boolean canStore( Object o ) {
    boolean result = false;

    // Clients may not ask how much room remains in the fridge.
    if( o instanceof PhysicalObject ) {
      PhysicalObject po = (PhysicalObject)o;

      // How the fridge determines its remaining usable volume is a detail.
      // How a physical object determines whether it fits within a specified
      // volume is also a detail.
      result = po.isEnclosedBy( getUsableVolume() );
    }

     return result;
  }

  /** Doesn't expose how the fridge knows its warranty has expired. */
  public boolean isPastWarranty() {
    return getWarranty().before( new Date() );
  }

  /** Doesn't expose how objects are stored in the fridge. */
  public synchronized void store( Object o ) {
    validateExpiration( o );

    // Can the object fit?
    if( canStore( o ) ) {
      getObjects().add( o );
    }
    else {
      throw FridgeFullException( o );
    }
  }

  /** Doesn't expose how objects are removed from the fridge. */
  public synchronized void remove( Object o ) {
    if( !getObjects().contains( o ) ) {
      throw new ObjectNotFoundException( o );
    }

    getObjects().remove( o );

    validateExpiration( o );
  }

  /** Lazily initialized list, an implementation detail. */
  private synchronized List getObjects() {
    if( this.list == null ) { this.list = new List(); }
    return this.list;
  }

  /** How object expiration is determined is also a detail. */
  private void validateExpiration( Object o ) {
    // Objects can answer whether they have gone past a given
    // expiration date. How each object "knows" it has expired
    // is a detail. The Fridge might use a scanner and
    // items might have embedded RFID chips. It's a detail hidden
    // by proper encapsulation.
    if( o implements Expires && ((Expires)o).expiresBefore( today ) ) {
      throw new ExpiredObjectException( o );
    }
  }

  /** This creates a copy of the warranty for immutability purposes. */
  private void setWarranty( Date warranty ) {
    assert warranty != null;
    this.warranty = new Date( warranty.getTime() )
  }
}

4
冷蔵庫の例をあまり真剣に受け取らないでください。:)実際の冷蔵庫はコンテナオブジェクトである必要があります。正確に何であるかを心配せずにオブジェクトを保持する方法を知っていると期待しています。IEそれはArrayListのようになります。それを冷蔵庫にするものについては、保存されたときにオブジェクトをディスクにシリアル化し、システム障害に耐えるようにします。OK。冷蔵庫の例を真剣に取り上げるのに十分です。
ウィンストンイーバート

6
しかし、冷蔵庫は有効期限を知っているべきではないので、チーズが悪くなったので、捨てるべきだということがわかりますか?:) OK、これを止めなければなりません!:)
ディマ

10
非常に興味深い議論冷蔵庫ロジックあなたはここで起こってんだ...
メイソンウィーラー

35
ハハ、私はそのための広告を見たいと思う:「それは真新しい種類の冷蔵庫である:そこにない何かをつかもうとするときそれはあなたに物を投げる!この方法あなたはそれを一度だけ試みる!あなたは心配する冷蔵庫に詰めて、冷蔵庫に違法行為を心配させてください!」
ギャブリン

42
この例ではすべて間違っています。AgeフィールドやsetAge()メソッドがあってはなりません。年齢は、ある時点と比較した場合のPerson birthDateの関数です。一見些細なように見えますが、これは、プライベートフィールドのget / setメソッドで見られるように、実際に変更可能なもの、フィールド、オブジェクト、オブジェクトその動作と実際に有効な状態変更(setXメソッドが完全に破壊する)について知っておく必要があります。
ダレルティーグ14

41

Javaのゲッターとセッターの基本的な理由は非常に簡単です。

  • インターフェイスでは、フィールドではなくメソッドのみを指定できます。

したがって、フィールドがインターフェイスを通過できるようにするには、リーダーメソッドとライターメソッドが必要です。これらは従来、フィールドxに対してgetXおよびsetXと呼ばれています。


44
それは言語の制限です。本当の問題は、他のオブジェクトがその状態を操作できるようにするかどうかです。
ウィンストンイーバート

3
@Peter Turner、明らかに、言語がプロパティを含むインターフェースを持つことを妨げるものは何もありません。ゲッター/セッターとして実装される可能性がありますが、プロパティのインターフェイス定義にサポートを追加するのは簡単です。
ウィンストンイーバート

2
@Winston、最終的にクラスが相互に情報をやり取りできるようにして、実際に作業を完了させる必要があります。代わりに何を提案しますか?

6
オブジェクトは、内部に高レベルのインターフェースを提供することになっています。ゲッターとセッターは、低レベルのインターフェイスである傾向があります。たとえば、バイナリツリーを実装するクラスがあるとします。ツリーをナビゲートするために、GetLeft()、GetRight()、GetValue()、GetKey()などの関数を使用できます。しかし、それは完全に間違ったアプローチです。バイナリツリークラスは、検索、挿入、削除などの操作を提供する必要があります。
ウィンストンイーバート

6
別の例を挙げると、テトリスのピースを考えてみましょう。テトリスのピースには、block_type、rotation、positionなどの内部状態があります。GetBlockType()、GetRotation()、GetPosition()などのゲッターを使用できます。しかし、あなたは本当にすべきではありません。必要なのは、このピースが占めるすべての正方形のリストを返すGetSquares()メソッドです。また、SetPosition()やSetRotation()のようなものを持ってはいけません。代わりに、MoveLeft()、MoveRight()、Rotate()、Fall()などの操作が必要です。
ウィンストンイーバート

20

http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_andから

JavaBeanスタイル:

connection.setUser("dukie");
connection.setPwd("duke");
connection.initialize();

オブジェクト指向スタイル:

connection.connect("dukie","duke");

まあ、明らかに、後者のアプローチを好む。実装の詳細に影響を与えず、よりシンプルで簡潔であり、必要なすべての情報がメソッド呼び出しに含まれているため、簡単に正しく実行できます。可能な限り、コンストラクターのパラメーターを使用してプライベートメンバーを設定することも好みます。

あなたの質問は、ゲッター/セッターが正当化されるのはいつですか?おそらく、モードの変更が必要な場合、または何らかの情報を得るためにオブジェクトを調べる必要がある場合です。

myObject.GetStatus();
myObject.SomeCapabilitySwitch = true;

それについて考えると、私が最初にC#でコーディングを始めたとき、上記のJavabeansスタイルで多くのコードを書きました。しかし、言語の経験を積むにつれて、コンストラクターでより多くのメンバーの設定を行い、上記のオブジェクト指向スタイルに似たメソッドを使用し始めました。


6
なぜ「すべての引数をパラメーターとして与える」オブジェクト指向スタイルなのですか?

5
あなたの「OOスタイル」は2つまたは3つのオプションには適していますが、それ以上になったらJavaBeanスタイルを好むでしょう。パラメータのすべての組み合わせのための20のオーバーロードされたメソッドを持つだけひどい見えます
TheLQ

1
@TheLQ:C#4.0は、コンストラクターとメソッド呼び出しでオプションのパラメーターと名前付きパラメーターを許可することで、これを容易にします。
ロバートハーヴェイ

7
@TheLQそれは流Builderな構文を持つBuilder の目的です。たとえばGuavaのMapMakerを参照してください。
-maaartinus

5
@ThorbjørnRavn Andersen、「すべての引数をパラメーターとして与える」は、「JavaBeanセッターを呼び出す」よりもオブジェクト指向スタイルの方が良いと思います。例でconnect(..)メソッドを使用しても、このような仮定は行われません。ユーザー属性とパスワード属性を設定する場合としない場合があります。重要なのは、正しいOOの概念である「接続」メッセージに焦点を合わせることです。
アンドレスF。

13

ゲッターとセッターはいつ正当化されますか?

動作 "get"および "set"が実際にモデルの動作と一致する場合(実際にはそうではありません)

ビジネスドメインの動作が明確ではないため、他のすべての使用は不正です。

編集

その答えはフリッパートとして出会ったかもしれないので、拡大させてください。上記の答えはほとんど正しいですが、オブジェクト指向設計のプログラミングパラダイムと全体像を見逃しているものに焦点を当てています。私の経験では、これにより、getsとsetterを避けることがOOプログラミング言語の学問的なルールであると考えるようになります(たとえば、ゲッターをプロパティに置き換えることは壮大だと思う人)

実際、それは設計プロセスの結果です。これらのパラダイムを破るのか、破らないのか、そしてオブジェクト指向プログラミングの良い点と悪い点について議論して、インターフェースやカプセル化、パターンに入る必要はありません。最終的に重要なのは、ドメインに何も存在しない場合、それらを配置することでこのように機能するのはドメインをモデル化しないことです。

現実には、ドメイン空間のどのシステムにもゲッターとセッターがあることはほとんどありません。給与計算を担当する男性または女性に近づいて、単に「この給与をXに設定」または「この給与を取得と言うことはできません。このような動作は単に存在しません

これをコードに組み込む場合、ドメインのモデルに一致するようにシステムを設計しているわけではありません。はい、それはインターフェイスとカプセル化を壊しますが、それはポイントではありません。ポイントは、存在しないものをモデリングしているということです。

さらに重要なステップやプロセスが欠落している可能性があります。これはおそらく、給与を支払ってこの給与をXに設定するだけではいけない理由があるからです。

ゲッターとセッターを使用する場合、このプロセスのルールを間違った場所にプッシュする傾向があります。これは、ドメインからさらに離れています。現実世界の例を使用すると、入ってきたランダムな人がこれらの値を取得する許可を持っていると仮定した場合の給与に似ています。そうでなければ、彼はそれらを求めません。それは、ドメインがどうであるかではないだけでなく、実際にはドメインがどうであるかについて嘘をついています。


ポイントが作ら前17件の答えで説明した上で、これはかなりのものを提供していないようだ
ブヨ

1
他の答えは、オブジェクト、インターフェース、および他の言語のパラダイムについて語っています。これは問題ありませんが、中心的な問題ではありません。ゲッターとセッターはいくつかのコーディング規則に違反しているだけでなく、主に、実際のモデルでこの動作に遭遇することはほとんどないため、悪いだけではありません。この点は、コーディングのベストプラクティスに関する議論で失われる傾向があります。
コーマックマルホール14

給与ではない場合、給与計算のインターフェースは何だと思いますset/getか?
ウィンストンユワート14

1
それらが承認レイヤーにラップされ、特定の外部エンティティに制限されている場合、それらはゲッターおよびセッターではありません。給与部門に給与を変更する方法がないと言っているわけではありませんが、その方法は会社自体の内部プロセスと整合する必要があります。たとえば、ほとんどの企業は、マネージャーによって承認された従業員契約に基づいて給与を設定します。従業員の給与が変わった場合、新しい契約が作成され、マネージャーはそれに署名する必要があります。したがって、給与計算は給与ロールを変更するには、契約の対象といくつかの権限オブジェクトを期待するべきである
コーマックMulhall

3
別の言い方をすれば、set_salary(new_salary、employee_id)とauthorized_salary_update(employee_contract、authorising_manager)にはかなりの違いがあります。プロセスは内部ビジネスプロセスをモデル化する必要があります
Cormac Mulhall

11

原則として、ゲッターとセッターは悪い考えです。フィールドが論理的にインターフェイスの一部ではなく、プライベートにした場合、それは問題ありません。論理的にインターフェイスの一部であり、それを公開する場合、それは問題ありません。しかし、それをプライベートにしてから向きを変えて、ゲッターとセッターを提供することで効果的に再び公開すると、コードはより冗長で難読化されていることを除いて、元の場所に戻ります。

明らかに、例外があります。Javaでは、インターフェイスを使用する必要がある場合があります。Java標準ライブラリには、コード品質の通常の測定値を上回るほど極端な下位互換性要件があります。インターフェースを壊さずに、後で保存されたフィールドをオンザフライの計算で置き換える可能性が高い、伝説的ではあるがまれなケースを実際に処理している可能性さえあります。しかし、これらは例外です。ゲッターとセッターは、特別な正当化を必要とするアンチパターンです。


6
ゲッターとセッターは、フィールドではなく属性がインターフェースの一部であることを意味します。getBirthDate()とSetBirthDate()が「yyyy / mm / dd」をとると仮定しますが、格納されるフィールドは1000年1月1日からの日数です。これを01/01/0001に変更すると、ゲッターとセッターはインターフェースを同じに保ちます。特に、「パブリック」とは公的にトラッシュ可能なことを意味するため、変数は決してパブリックであってはなりません。常にセッターを使用して着信値を検証し、関連するフィールドを更新し、必要に応じて変換するなど。内部ストレージが変更された場合にゲッターを使用してみてください。
アンディキャンフィールド

@AndyCanfieldは、パブリックとは一般にゴミ箱に入れられることを意味しますが、それはあなたがそれをひどくプログラムした場合にのみそうです。セッターがあり、間違った値が送信された場合、uは例外をスローする可能性がありますが、例外をスローしてプログラムを破壊することもできますが、エラーで終了しますまた、オブジェクトのユーザーが変数に値を与えてcudが間違っている場合値は、それを念頭に置いてテストすることができます。「ああ、しかし、セッターを使用する場合は1つのテストを行うだけです」と言うかもしれませんが、ウル独自のコードは変数に悪い値を与えます。 tests.nをテストで削減します。urprogは「ゴミ箱」になりません
-barlop

3

フィールドに直接アクセスできるか、メソッドを介してアクセスできるかは本当に重要ではありません。

クラスの不変式(有用なもの)は重要です。そして、それらを保存するために、外部から何かを変更できないようにする必要がある場合があります。例えば。幅と高さが別々のクラスSquareがある場合、それらのいずれかを変更すると、正方形以外のものになります。したがって、changeSideメソッドが必要です。これがRectangleの場合、setter / publicフィールドを持つことができます。しかし、セッターはゼロより大きい方が良いかどうかをテストします。

そして、具体的な言語(例えば、java)では、これらのメソッド(インターフェース)が必要な理由です。メソッドのもう1つの理由は、互換性(ソースとバイナリ)です。したがって、それらを簡単に追加してから、パブリックフィールドで十分かどうかを考えます。

ところで。私は、public finalフィールドを持つ単純な不変の値保持クラスを使用するのが好きです。


これはほとんど避けるべき唯一のものです。フィールドからプロパティ/ゲッター/セッターに移動することは、ほとんどの言語で重大な変更です。
MrDosu 14

2

インターフェイスを同じに保ちながら、内部を何にでも変更したい場合があります。インターフェイスが変化しない場合、コードは壊れません。必要に応じて内部を変更できます。


1
この答えがずっと下にあることに驚いています。ゲッターとセッターを使用すると、既存のAPIを壊すことなく、将来、より多くのことを実行できます(たとえば、イベントの発生、入力の検証の追加、内部簿記の実行)。非公開コードであっても、変更する必要のあるAPIの数が少ないほど、更新する依存関係が少なくなり、更新を行う際に導入されるバグが少なくなります。
AmadeusDrZaius

0

私のアプローチはこれです-

後でデータをいじるつもりなら、ゲッター/セッターが正当化されます。また、変更が発生している場合は、データをゲッター/セッターにプッシュすることがよくあります。

POD構造の場合、スロットは使用可能のままにします。

より抽象的なレベルでは、問題は「誰がデータを管理するか」であり、それはプロジェクトに依存します。


0

ゲッターとセッターの使用が複雑に感じる場合、問題は言語ではなく概念そのものである可能性があります。

次に、Rubyで記述された2番目の例のコードを示します。

class Fridge
  attr_accessor :cheese
end

def go_shopping fridge
  fridge.cheese += 5
end

Javaの最初の例によく似ていることに注意してください。ゲッターとセッターがファーストクラスの市民として扱われる場合、それらは使用するのは面倒ではなく、追加された柔軟性は時には大きな恩恵になることがあります-たとえば、新しい冷蔵庫でチーズのデフォルト値を返すことができます:

class Fridge
  attr_accessor :cheese

  def cheese
    @cheese || 0
  end
end

もちろん、まったく公開されるべきではない多くの変数があります。内部変数を不必要に公開するとコードが悪化しますが、ゲッターとセッターでそれを責めることはほとんどできません。


それは美しく述べられています。徐々にレシピを構築しながら不変オブジェクトを作成するため、ビルダー関数が追加されました。おそらく、人工甘味料を追加する場合、砂糖を追加する必要はありません。名前付きパラメーターを使用し、オーバーロードしても、すべてを実行する1つのメソッドを構築することは非常に困難です。そしてもちろん、javaには名前付きパラメーターがないため、人々がBuilderパターンを使用するもう1つの理由があります。
ヨーヨー

0

Size幅と高さをカプセル化するクラスを考えてください。コンストラクタを使用してセッターを削除できますが、どのようにして長方形を描くのに役立ちますSizeか?幅と高さはクラスの内部データではありません。サイズの消費者が利用できる共有データです。

オブジェクトは、動作と状態(または属性)で構成されます。公開された状態がない場合、動作のみが公開されます。

状態がなければ、オブジェクトのコレクションをどのようにソートしますか?オブジェクトの特定のインスタンスをどのように検索しますか?コンストラクタのみを使用する場合、オブジェクトに属性の長いリストがあるとどうなりますか?

検証なしでメソッドパラメータを使用することはできません。したがって、書くのは怠です:

setMyField(int myField){
    this.myField = myField;
}

そのように記述すれば、少なくともセッターを検証に使用する準備ができています。パブリックフィールドよりも優れていますが、かろうじてです。ただし、少なくとも一貫したパブリックインターフェイスがあり、顧客のコードを壊すことなく戻って検証ルールを設定できます。

ゲッター、セッター、プロパティ、ミューテーター、それらをあなたが望むものと呼びますが、それらは必要です。


ただし、少なくとも一貫したパブリックインターフェイスがあり、顧客のコードを壊すことなく戻って検証ルールを設定できます。それは真実ではない。さらに先に検証ルールを追加すると、「顧客のコードを破る」可能性が非常に高くなります。テイクint例えば、インスタンス変数を、あなたが唯一の非負値を受け入れるに検証ルールを追加することを決定したことを想像してみてください。問題は、顧客のコードが既に負の値に設定する可能性に依存している可能性があることです
...-jub0bs

0

ゲッターとセッターがカプセル化と真のオブジェクト指向に違反する場合、私は真剣に困っています。

私はいつも、オブジェクトは、あなたがそれをするために必要だと思い浮かぶ最高のものを表しています。

JavaでMazeを生成するプログラムの作成を終えたばかりで、「Maze Squares」を表すクラスがあります。このクラスには、座標、壁、ブール値などを表すデータがあります。

このデータを変更/操作/アクセスするには何らかの方法が必要です!ゲッターとセッターなしで何をしますか?Javaはプロパティを使用せず、このクラスのローカルにあるすべてのデータをパブリックに設定することは、明らかにカプセル化とオブジェクト指向の違反です。


6
ここに質問があります:これらすべてのフィールドを公開し、ゲッターとセッターの使用を停止した場合、コードはどのように異なりますか?
ウィンストンイーバート

理論的には、そうではありません。なぜその時点でクラスを作成するのでしょうか?何でも同じ議論ができます。しかし、私の下の投稿はもっとエレガントに言っているようです。(ゲッターとセッターは安全にオブジェクトに値を渡し、またはそのオブジェクトから値を取得する方法です。)ポストが進む...
ブライアン・ハリントン

3
私は指摘したい:そのポスターは最終的に私に同意し、その効果に対する別の答えを投稿した。基本的に、ゲッターとセッターを使用することは、データを直接操作することと同じです。あなたはそれをすることで実際にオブジェクト指向性を得ることはありません。オブジェクト指向になるには、データへのより高いレベルのインターフェイスを提供する必要があります。
ウィンストンイーバート

4
それを説明する最良の方法は、インターフェースを内側からではなく外側から設計するべきだと言うことだと思います。オブジェクトが提供するインターフェイスは、実装方法ではなく、オブジェクトの使用方法によって決定される必要があります。そのため、ゲッターを記述せず、外部オブジェクトがデータを解釈できるようにします。回答が必要な質問を見つけ、その質問に回答するメソッドを記述します。外部オブジェクトがセッターによって状態を変更することを許可しないでください。外部オブジェクトが実行する必要がある操作の種類を見つけ、それを行うメソッドを記述します。
ウィンストンイーバート

2
場合によっては、ゲッターとセッターが最良の方法です。時々、それらはあなたが提供できる最高のインターフェースです。ただし、多くの場合、そうではありません。多くの場合、実装の詳細を他のクラスに漏らしているだけです。
ウィンストンイーバート

-1

まず、私がコメントするオブジェクトには、値とサービスのタイプの2種類があります。

サービスタイプにセッターを含めることはできません。必要な依存関係は取得できません。依存関係を渡す最良の方法は、コンストラクターまたはファクトリーを使用することです。この方法では、すべてのインスタンスが最初から完全に形成され、単純で単純です。

値の型も不変である必要があります。一方で、ORMのように実用的ではない場合や、ウィジェットからオブジェクトへのマッピングなど、他のマッピングもあります。あるレイヤーまたはパーツから別のレイヤーまたはシステムにシステムを渡される他のすべての値タイプは不変である必要があり、セッターを持つべきではありません。


3番目のタイプをお勧めします。1つ以上の値を保持することを目的とする可変コンテナーです。多くの場合、コンテナはロジックや検証の面で多くのことを期待すべきではありません。6個の正の整数を計算するメソッドを必要とするコードは、6個の整数のコンテナをメソッドに渡し、そこに結果を保存します。数値が正であることを確認する責任は、一般的に、コンテナではなく、呼び出し元または呼び出されたメソッドのいずれかにあります。
スーパーキャット

-1

ゲッター/セッターは、他のパブリックメソッドが正当化されるように正当化されます。正当化の主な理由は、クラスが他のクラスと相互作用する方法を定義する外部世界へのインターフェイスを提供するためです。これは主に、個別のエンティティ間の結合を減らしたいためです。カップリングを減らすことは多くの理由で良いことです:

  • 現在のコードから同じクラスインターフェイスを使用できますが、そのクラスは新しいメソッドを追加しました(ただし、古いインターフェイスは保持されます)
  • 消費者に影響を与えることなく、クラスの内部表現を変更できます
  • バグの可能性を減らす:内部データをプライベートにすると、外部コードが内部データを混乱させないことが確実にわかります。

-1

はい、ゲッターとセッターは、オブジェクト指向プログラミングにおけるアンチパターンであるとすべき決して使用しないこと:http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html。簡単に言えば、オブジェクトをデータ構造のように扱うことを奨励するため、オブジェクト指向のパラダイムには適合しません。これは大きな誤解です。


2
ポイントが作られ、前18件の答えで説明した上で、これはかなりのものを提供していないようだ
ブヨ

4
また、決して言うことは少し強い。
ウィンストンユワート

-4

プログラミング言語の自動生成を行う会社が開発したIDEが「オブジェクト指向の原則」に違反しないことを願っています。

そうは言っても、パブリックスコープ変数を取得したら、ゲッターとセッターを使用してください。私は、非常にオブジェクト指向のカプセル化の原則の必要な要素であるように思えます-たとえ多くのジャンクコードのように見えても。

それらを使用する理由は、適切なカプセル化がまだ行われている可能性があり、オブジェクトと猿をしている人があなたのオブジェクトを感じることができるレイヤーを抽象化する限り、彼は正しいことさえ知らずにそのオブジェクトを取り去ることができますか?

分割された家は我慢できず、OOのテナントの1つはオンにならず、カプセル化と時期尚早な最適化の両方を提供することはできません。


4
そして、変数を扱うたびにsetFoo()とgetFoo()を呼び出すために多くのコードを追加することで、正確に何が得られましたか?
ウィンストンイーバート

7
カプセル化されるとは思わない。あなたはまだ他の場所からオブジェクトの状態を操作しています。あなたはもっと冗長にやっているだけです。カプセル化を実現するには、その値を所有するクラスの値の操作を集中化する必要があります。それ以外は、オブジェクト指向の衣服の手続きコードです。(必ずしもそれが間違っているわけではありませんが、それが何であるかです)。
ウィンストンイーバート

2
カプセル化の利点は、特定の値に関連するすべてのロジックが1か所(多かれ少なかれ)にあることです。私はゲッターとセッターでそれを取得しません。したがって、私は彼らに多くの利益を得るとは思わない。
ウィンストンイーバート

1
ただし、ゲッターとセッターを使用して、パブリックアクセスを介してデータを自由に操作するコードを使用することに同意します。そうすれば、少なくとも着信データの検証を添付できます。
ウィンストンイーバート

3
私は確かに冗長性のファンではありません。しかし、私の反対は、変数をプライベートにしてから、それらのゲッターとセッターを自由に呼び出して、最終的にはほとんど違いがないという人々です。クラス内でゲッター/セッターを使用する場合は問題ありません。問題はなぜですか?私が認識している主な利点は、データを検証してエラーを早期にキャッチできることです。データを操作するすべてのコードが同じ場所にある場合、これはあまり役に立ちません。しかし、それはまだ役に立ちます。理想的には、プロパティをサポートし、冗長性を回避できる言語が必要です。
ウィンストンイーバート

-4

ここでもっと普通の答えがあると思いましたか?

ゲッターとセッターは一般的に極端にOOPです(他の何かが間違っていると言う人は誰でも、そのように単純です)。

オーバーエンジニアしないように注意する必要がありますが、必要のないゲッターやセッターを作成しないでください。別のクラスで使用する予定のない情報で、ゲッターやセッターを使用しないでください。

ただし、フィールドをパブリックにせず、代わりにゲッターとセッターを持つ理由はほとんどです:

  • フィールドを使用して適切なテストを行うことはできません。ゲッター/セッターはその点ではるかに優れています。

  • リアルタイムプログラミング設定でフィールドを適切に使用することは不可能です。同期ゲッター/セッターを使用する方法です。

  • インターフェイストピック(既に説明しているので、説明しません)。

  • システムを適切に再利用するときに使いやすくなります。

  • クラスを使用しているクラスと、フィールドを変更した場合に破損するものをゲッター/セッターよりも知ることははるかに困難です。

そのため、ゲッター/セッターの代わりにパブリックフィールドを使用するのは、公式プロジェクトを作成するのではなく、単に楽しみのためにゲッター/セッターに煩わされないときだけです。


2
テスト可能性のために+1。誰も以前に言及していないことにショックを受けました。プロパティのもう1つの便利な機能は、デバッグです。(フィールドにハードウェア/メモリブレークポイントを必要とするよりも、コードにブレークポイントを挿入する方がはるかに簡単です)。
マークH

9
ゲッターとセッターに対する反対は、彼らが精神と意図を無視してOOP法の手紙に従うためにしばしば使われるということです。OOPには、他のオブジェクトが内部をマックすることを許可すべきでないと書かれています。とにかくそれを可能にするゲッターとセッターを定義すると、OOPに違反することになります。
ウィンストンイーバート

6
ゲッターとセッターには、単純なパブリックフィールドよりも多くの利点があることに同意します。ただし、テストがどのように優れているかは明確ではありません。説明してもらえますか?
ウィンストンイーバート

4
@スカリオン:あなたの答えに同意しません。ゲッター/セッターを使用するか、フィールドをパブリックにするかの2つの選択肢を提示しているようです。しかし、3番目のオプションがあります。ゲッター/セッターを使用せず、フィールドを公開しません!内部フィールドの状態をテストする必要があるのはなぜですか?オブジェクトのパブリックAPIをテストするべきではありませんか?
アンドレスF。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.