1733

これらの変数にパブリックフィールドを使用するのではなく、取得と設定のみを行うゲッターとセッターを使用する利点は何ですか?

ゲッターとセッターが単純なget/set以上のことをしている場合、これは非常に迅速に理解できますが、その方法について100%明確ではありません。

public String foo;

以下よりも悪いです:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

前者はボイラープレートコードがはるかに少なくて済みます。

4

41 に答える 41

1125

クラスのフィールドを直接公開するのではなく、アクセサの使用を検討する理由は実際にはたくさんあります。カプセル化の議論だけでなく、将来の変更を容易にすることもできます。

これが私が知っている理由のいくつかです:

  • プロパティの取得または設定に関連する動作のカプセル化-これにより、追加機能(検証など)を後で簡単に追加できます。
  • 代替表現を使用してプロパティを公開している間、プロパティの内部表現を非表示にします。
  • パブリックインターフェイスを変更から保護する-実装が変更されても、既存のコンシューマーに影響を与えることなく、パブリックインターフェイスを一定に保つことができます。
  • プロパティの有効期間とメモリ管理(廃棄)セマンティクスの制御-管理されていないメモリ環境(C ++やObjective-Cなど)では特に重要です。
  • 実行時にプロパティが変更されたときのデバッグインターセプトポイントを提供します。一部の言語では、これがないと、プロパティが特定の値に変更されたときと場所のデバッグが非常に困難になる可能性があります。
  • プロパティゲッター/セッターに対して動作するように設計されたライブラリとの相互運用性の向上-モッキング、シリアル化、およびWPFが思い浮かびます。
  • getter / setterメソッドをオーバーライドすることにより、継承者がプロパティの動作と公開のセマンティクスを変更できるようにします。
  • ゲッター/セッターを値ではなくラムダ式として渡すことができます。
  • ゲッターとセッターは、異なるアクセスレベルを許可できます。たとえば、getはパブリックである可能性がありますが、セットは保護されている可能性があります。
于 2009-10-14T18:47:55.443 に答える
574

セッターが値を設定する以上のことを行う必要があることに気付いた今から2週間(月、年)なので、プロパティが他の238のクラスで直接使用されていることにも気付くでしょう:-)

于 2009-10-14T18:23:19.590 に答える
406

パブリックフィールドは、フィールドを返してそれに割り当てる以外に何もしないゲッター/セッターのペアよりも悪くはありません。まず、(ほとんどの言語で)機能的な違いがないことは明らかです。違いは、保守性や読みやすさなどの他の要素にある必要があります。

ゲッター/セッターのペアのよく言われる利点はそうではありません。実装を変更でき、クライアントを再コンパイルする必要がないという主張があります。おそらく、セッターを使用すると、後で検証などの機能を追加でき、クライアントはそれについて知る必要さえありません。ただし、セッターに検証を追加すると、前提条件が変更され、以前のコントラクトに違反します。これは、「ここに何でも入れることができ、後でゲッターから同じものを取得できる」というものでした。

したがって、契約を破ったので、コードベース内のすべてのファイルを変更することは、避けてはいけないことです。それを回避すると、すべてのコードがそれらのメソッドのコントラクトが異なると想定していると想定していることになります。

それが契約であるべきではなかった場合、インターフェースはクライアントがオブジェクトを無効な状態にすることを許可していました。これはカプセル化の正反対です。そのフィールドを最初から実際に何にも設定できなかった場合、最初から検証が行われなかったのはなぜですか。

この同じ議論は、これらのパススルーゲッター/セッターペアの他の想定される利点にも当てはまります。後で設定する値を変更することにした場合、契約を破ることになります。派生クラスのデフォルト機能を、いくつかの無害な変更(ロギングやその他の観察できない動作など)を超えた方法でオーバーライドすると、基本クラスのコントラクトが破られます。これは、OOの信条の1つと見なされているリスコフの置換原則の違反です。

クラスがすべてのフィールドに対してこれらのダムゲッターとセッターを持っている場合、それは不変条件やコントラクトをまったく持たないクラスです。それは本当にオブジェクト指向のデザインですか?クラスにあるのがそれらのゲッターとセッターだけである場合、それは単なるダムデータホルダーであり、ダムデータホルダーはダムデータホルダーのように見えるはずです。

class Foo {
public:
    int DaysLeft;
    int ContestantNumber;
};

このようなクラスにパススルーゲッター/セッターのペアを追加しても、価値はありません。他のクラスは、フィールドがすでに提供している操作だけでなく、意味のある操作を提供する必要があります。これが、有用な不変条件を定義および維持する方法です。

クライアント:「このクラスのオブジェクトで何ができますか?」
デザイナー:「いくつかの変数を読み書きできます。」
クライアント:「ああ...かっこいいね?」

ゲッターとセッターを使用する理由はありますが、それらの理由が存在しない場合、誤ったカプセル化の神の名前でゲッター/セッターのペアを作成することは良いことではありません。ゲッターまたはセッターを作成する正当な理由には、検証やさまざまな内部表現など、後で行うことができる潜在的な変更としてよく言及されるものが含まれます。または、値はクライアントによって読み取り可能であるが書き込み可能ではない(たとえば、辞書のサイズを読み取る)必要があるため、単純なゲッターが適切な選択です。しかし、これらの理由は、後で必要になる可能性があるものとしてだけでなく、選択するときに存在する必要があります。これはYAGNI(You Ai n't Gonna Need It)のインスタンスです。

于 2012-08-24T10:55:13.003 に答える
106

多くの人がゲッターやセッターの利点について話しますが、私は悪魔の代弁者を演じたいと思っています。現在、私は非常に大規模なプログラムをデバッグしており、プログラマーはすべてをゲッターとセッターにすることにしました。それはいいことのように思えるかもしれませんが、リバースエンジニアリングの悪夢です。

数百行のコードを調べていて、これに遭遇したとします。

person.name = "Joe";

セッターに気付くまでは、美しくシンプルなコードです。ここで、そのセッターをたどると、person.firstName、person.lastName、person.isHuman、person.hasReallyCommonFirstNameも設定され、person.update()が呼び出されて、データベースなどにクエリが送信されることがわかります。メモリリークが発生していた場所。

ローカルのコードを一目で理解することは、ゲッターとセッターが壊れがちな読みやすさの重要な特性です。そのため、可能な限りそれらを避け、使用するときにそれらが行うことを最小限に抑えようとしています。

于 2009-10-14T21:00:47.610 に答える
68

純粋なオブジェクト指向の世界では、ゲッターとセッターはひどいアンチパターンです。この記事を読む:ゲッター/セッター。悪。期間。一言で言えば、それらはプログラマーがデータ構造のようにオブジェクトについて考えることを奨励し、このタイプの考え方は純粋な手続き型です(COBOLやCのように)。オブジェクト指向言語にはデータ構造はありませんが、動作を公開するオブジェクトのみがあります(属性/プロパティではありません!)

それらの詳細については、Elegant Objectsのセクション3.5 (オブジェクト指向プログラミングに関する私の本)を参照してください。

于 2014-09-23T16:39:19.837 に答える
57

多くの理由があります。私のお気に入りは、動作を変更したり、変数に設定できるものを調整したりする必要がある場合です。たとえば、setSpeed(int speed)メソッドがあるとします。ただし、最大速度を100にしか設定できないようにする必要があります。次のようにします。

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}

コードのどこでもパブリックフィールドを使用していて、上記の要件が必要であることに気付いた場合はどうでしょうか。セッターを変更するだけでなく、パブリックフィールドのすべての使用法を探して楽しんでください。

私の2セント:)

于 2009-10-14T18:27:22.733 に答える
40

アクセサーとミューテーターの利点の1つは、検証を実行できることです。

たとえば、fooパブリックの場合、簡単に設定してnull、他の誰かがオブジェクトのメソッドを呼び出そうとすることができます。しかし、それはもうありません!setFooメソッドを使用すると、それがに設定されていないことを確認できましfoonull

アクセサーとミューテーターはカプセル化も可能にします-一度設定された値を表示する必要がない場合(おそらく、コンストラクターで設定されてメソッドによって使用されますが、変更されることはありません)、誰にも表示されません。ただし、他のクラスに表示または変更を許可できる場合は、適切なアクセサーおよび/またはミューテーターを提供できます。

于 2009-10-14T18:25:11.387 に答える
29

あなたの言語に依存します。あなたはこの「Java」ではなく「オブジェクト指向」にタグを付けたので、ChssPly76の答えは言語に依存していることを指摘したいと思います。たとえば、Pythonでは、ゲッターとセッターを使用する理由はありません。動作を変更する必要がある場合は、基本的な属性アクセスの周りにゲッターとセッターをラップするプロパティを使用できます。このようなもの:

 class Simple(object):
   def _get_value(self):
       return self._value -1

   def _set_value(self, new_value):
       self._value = new_value + 1

   def _del_value(self):
       self.old_values.append(self._value)
       del self._value

   value = property(_get_value, _set_value, _del_value)
于 2009-10-14T18:32:01.810 に答える
28

おかげで、それは私の考えを本当に明確にしました。ここに、ゲッターとセッターを使用しない(ほぼ)10の(ほぼ)正当な理由があります。

  1. 値を設定して取得する以上のことを行う必要があることに気付いた場合は、フィールドをプライベートにするだけで、直接アクセスした場所がすぐにわかります。
  2. そこで実行する検証は、文脈自由でしかあり得ません。この検証が実際に行われることはめったにありません。
  3. 設定されている値を変更できます。これは、発信者が[ショックホラー]でそのまま保存してほしい値を渡した場合の絶対的な悪夢です。
  4. 内部表現を非表示にすることができます-素晴らしいので、これらすべての操作が対称的であることを確認していますか?
  5. パブリックインターフェイスをシートの下の変更から隔離しました。インターフェイスを設計していて、何かに直接アクセスできるかどうかわからない場合は、設計を続ける必要があります。
  6. 一部のライブラリはこれを期待していますが、多くはありません-リフレクション、シリアル化、モックオブジェクトはすべてパブリックフィールドで問題なく機能します。
  7. このクラスを継承すると、デフォルトの機能をオーバーライドできます。つまり、実装を非表示にするだけでなく、一貫性を失わせることで、呼び出し元を本当に混乱させる可能性があります。

私が去る最後の3つ(N/AまたはD/C)...

于 2012-03-27T03:53:26.930 に答える
26

変数/オブジェクトのカプセル化とセキュリティに必要な場合もありますが、実際のオブジェクト指向プログラムをコーディングする場合は、アクセサリの使いすぎをやめる必要があります。本当に必要ではないときにそれらに適用すると、変数を公開するのとほぼ同じになります。

于 2012-08-22T14:47:41.587 に答える
23

少し遅いとは思いますが、パフォーマンスに興味のある方もいらっしゃると思います。

少しパフォーマンステストを行いました。整数を保持するクラス「NumberHolder」を作成しました。anInstance.getNumber()getterメソッドを使用するか、。を使用して数値に直接アクセスすることにより、その整数を読み取ることができます anInstance.number。私のプログラムは、両方の方法で数値を1,000,000,000回読み取ります。そのプロセスが5回繰り返され、時間が印刷されます。次の結果が得られました。

Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms

(時間1は直接の方法であり、時間2はゲッターです)

ほら、ゲッターは(ほとんど)常に少し速いです。次に、さまざまなサイクル数で試してみました。100万の代わりに、1000万と10万を使用しました。結果:

1000万サイクル:

Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms

1000万サイクルで、時間はほぼ同じです。これが10万(10万)サイクルです:

Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms

また、サイクルの量が異なると、ゲッターは通常の方法よりも少し速くなります。これがお役に立てば幸いです。

于 2016-08-30T18:59:35.140 に答える
22

編集:これを尋ねるプログラミングを学ぶ人がたくさんいるので、私はこの質問に答えました、そして答えのほとんどは非常に技術的に有能です、しかしあなたが初心者であるならば彼らは理解するのが簡単ではありません。私たちはみんな初心者だったので、もっと初心者に優しい答えを試してみようと思いました。

主な2つは、ポリモーフィズムと検証です。たとえそれが単なる愚かなデータ構造であっても。

この単純なクラスがあるとしましょう:

public class Bottle {
  public int amountOfWaterMl;
  public int capacityMl;
}

液体の量と容量(ミリリットル)を保持する非常に単純なクラス。

私がするとどうなりますか:

Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacityMl = 1000;

まあ、あなたはそれがうまくいくとは思わないでしょう?ある種の健全性チェックが必要です。さらに悪いことに、最大容量を指定しなかった場合はどうなりますか?ああ、問題があります。

しかし、別の問題もあります。ボトルが単なる1種類の容器だったとしたらどうでしょうか。容量と量の液体がすべて充填された複数のコンテナがある場合はどうなりますか?インターフェイスを作成できれば、プログラムの残りの部分にそのインターフェイスを受け入れさせることができ、ボトル、ジェリカン、およびあらゆる種類のものが同じように機能します。それは良いことではないでしょうか?インターフェイスはメソッドを必要とするため、これも良いことです。

最終的には次のようになります。

public interface LiquidContainer {
  public int getAmountMl();
  public void setAmountMl(int amountMl);
  public int getCapacityMl();
}

素晴らしい!そして今、Bottleをこれに変更します:

public class Bottle extends LiquidContainer {
  private int capacityMl;
  private int amountFilledMl;

  public Bottle(int capacityMl, int amountFilledMl) {
    this.capacityMl = capacityMl;
    this.amountFilledMl = amountFilledMl;
    checkNotOverFlow();
  }

  public int getAmountMl() {
    return amountFilledMl;
  }

  public void setAmountMl(int amountMl) {
     this.amountFilled = amountMl;
     checkNotOverFlow();
  }
  public int getCapacityMl() {
    return capacityMl;
  }

  private void checkNotOverFlow() {
    if(amountOfWaterMl > capacityMl) {
      throw new BottleOverflowException();
    }
}

BottleOverflowExceptionの定義は、読者の練習問題として残しておきます。

ここで、これがどれほど堅牢であるかに注目してください。ボトルの代わりにLiquidContainerを受け入れることで、コード内のあらゆるタイプのコンテナーを処理できるようになりました。そして、これらのボトルがこの種のものをどのように扱うかは、すべて異なる可能性があります。ディスクが変更されたときに状態をディスクに書き込むボトル、またはSQLデータベースまたはGNUに保存するボトルが他に何を知っているかを指定できます。

そして、これらはすべて、さまざまなフープを処理するためのさまざまな方法を持つことができます。ボトルはチェックするだけで、オーバーフローしている場合はRuntimeExceptionをスローします。しかし、それは間違ったことかもしれません。(エラー処理については有益な議論がありますが、ここでは意図的に非常に単純にしています。コメントの人々は、この単純なアプローチの欠陥を指摘する可能性があります。;))

そして、はい、私たちは非常に単純なアイデアからはるかに良い答えをすばやく得ることに移行しているようです。

ボトルの容量は変更できませんのでご注意ください。今では石になっています。これは、intでfinalと宣言することで実行できます。ただし、これがリストの場合は、リストを空にしたり、新しいものを追加したりすることができます。内臓に触れることへのアクセスを制限することはできません。

誰もが対処しているわけではない3番目のこともあります。ゲッターとセッターはメソッド呼び出しを使用します。つまり、他の場所では通常の方法のように見えます。DTOなどに奇妙な特定の構文を使用する代わりに、どこでも同じものを使用できます。

于 2015-11-29T14:37:50.397 に答える
18

ゲッターとセッターを使用します。

  • 再利用性のために
  • プログラミングの後の段階で検証を実行する

getterメソッドとsetterメソッドは、プライベートクラスメンバーにアクセスするためのパブリックインターフェイスです。


カプセル化のマントラ

カプセル化のマントラは、フィールドをプライベートにし、メソッドをパブリックにすることです。

ゲッターメソッド: プライベート変数にアクセスできます。

セッターメソッド: プライベートフィールドを変更できます。

getterメソッドとsetterメソッドは新しい機能を追加しませんが、後で考えを変えてそのメソッドを作成することができます。

  • より良い;
  • より安全; と
  • もっと早く。

値を使用できる場所であればどこでも、その値を返すメソッドを追加できます。それ以外の:

int x = 1000 - 500

使用する

int x = 1000 - class_name.getValue();

素人の言葉で

の表現

この詳細を保存する必要があるとしPersonます。これPersonには、、、およびのフィールドnameageありsexます。nameこれを行うには、、、ageおよびのメソッドを作成する必要がありsexます。ここで、別の人を作成する必要がある場合は、、、のメソッドをもう一度作成する必要がnameありageますsex

これを行う代わりに、class(Person)getterメソッドとsetterメソッドを使用してBeanを作成できます。したがって、明日はclass(Person class)、新しい人を追加する必要があるときはいつでも、このBeanのオブジェクトを作成できます(図を参照)。したがって、Beanクラスのフィールドとメソッドを再利用しています。これははるかに優れています。

于 2013-09-02T06:51:04.440 に答える
17

私はJavaの場合についてこれを熟考するのにかなりの時間を費やしましたが、本当の理由は次のとおりです。

  1. 実装ではなく、インターフェースへのコード
  2. インターフェイスはメソッドのみを指定し、フィールドは指定しません

つまり、インターフェイスでフィールドを指定できる唯一の方法は、新しい値を書き込むためのメソッドと現在の値を読み取るためのメソッドを提供することです。

それらのメソッドは、悪名高いゲッターとセッターです。

于 2009-11-07T21:55:17.913 に答える
16

現在の配信に必要な場合を除いて、ゲッターセッターを使用しないでください。つまり、ほとんどの本番アプリケーション、システムで変更が必要な場合は、将来何が起こるかについてあまり考えないでください。

シンプルで簡単に考え、必要に応じて複雑さを追加します。

私は、それが正しいと思う、またはアプローチが好きであるという理由だけで、深い技術的ノウハウのビジネスオーナーの無知を利用しません。

私は、アクセス修飾子と、n実行ビズロジックを検証するためのいくつかのメソッドのみを使用して、ゲッターセッターなしで作成された大規模なシステムを持っています。どうしても必要な場合。何でも使用してください。

于 2012-07-14T16:20:27.423 に答える
15

遅延読み込みに役立ちます。問題のオブジェクトがデータベースに保存されていて、必要でない限り取得したくないとします。オブジェクトがゲッターによって取得された場合、誰かがそれを要求するまで内部オブジェクトはnullになる可能性があり、その後、ゲッターへの最初の呼び出しでそれを取得することができます。

渡されたプロジェクトにベースページクラスがあり、いくつかの異なるWebサービス呼び出しからいくつかのデータを読み込んでいましたが、それらのWebサービス呼び出しのデータがすべての子ページで常に使用されるとは限りませんでした。Webサービスは、すべての利点のために、「遅い」の新しい定義を開拓しているので、必要がなければWebサービスを呼び出したくありません。

パブリックフィールドからゲッターに移動しました。ゲッターはキャッシュをチェックし、キャッシュがない場合はWebサービスを呼び出します。そのため、少しラッピングすることで、多くのWebサービス呼び出しが防止されました。

したがって、ゲッターを使用すると、各子ページで必要なものを見つけようとする必要がなくなります。必要な場合はゲッターに電話しますが、まだ持っていない場合はゲッターが探しに行きます。

    protected YourType _yourName = null;
    public YourType YourName{
      get
      {
        if (_yourName == null)
        {
          _yourName = new YourType();
          return _yourName;
        }
      }
    }
于 2009-10-14T19:08:30.457 に答える
14

これまでの回答で見逃した1つの側面、アクセス仕様:

  • メンバーの場合、設定と取得の両方のアクセス仕様は1つだけです。
  • セッターとゲッターの場合は、微調整して個別に定義できます
于 2009-10-14T18:38:28.367 に答える
11

「プロパティ」(C ++、Java)をサポートしていない言語、またはフィールドをプロパティ(C#)に変更するときにクライアントの再コンパイルが必要な言語では、get/setメソッドを使用すると変更が簡単になります。たとえば、検証ロジックをsetFooメソッドに追加する場合、クラスのパブリックインターフェイスを変更する必要はありません。

「実際の」プロパティをサポートする言語(Python、Ruby、おそらくSmalltalk?)では、メソッドを取得/設定する意味がありません。

于 2009-10-14T18:25:25.670 に答える
6

オブジェクト指向デザインの基本原則の1つ:カプセル化!

これには多くの利点があります。その1つは、ゲッター/セッターの実装をバックグラウンドで変更できることですが、データ型が同じである限り、その値のコンシューマーは引き続き機能します。

于 2009-10-14T18:25:19.320 に答える
5

次の場合にゲッターとセッターを使用する必要があります。

  • 概念的には属性であるものを扱っていますが、次のようになります。
    • あなたの言語にはプロパティ(またはTclの変数トレースのようないくつかの同様のメカニズム)がありません、または
    • あなたの言語のプロパティサポートは、このユースケースには十分ではありません、または
    • あなたの言語(または時にはあなたのフレームワーク)の慣用句は、このユースケースのゲッターまたはセッターを奨励します。

したがって、これが一般的なOOの質問になることはめったにありません。これは言語固有の質問であり、言語ごとに(およびユースケースごとに)異なる回答があります。


オブジェクト指向理論の観点からは、ゲッターとセッターは役に立ちません。クラスのインターフェースは、その状態ではなく、その機能です。(そうでない場合は、間違ったクラスを記述しました。)非常に単純なケースでは、クラスが行うことは、たとえば、長方形の座標でポイントを表すだけです*。属性はインターフェイスの一部です。ゲッターとセッターはそれを曇らせます。しかし、非常に単純な場合を除いて、属性もゲッターおよびセッターもインターフェースの一部ではありません。

別の言い方をすれば、クラスのコンシューマーが自分がspam属性を持っていることさえ知らないはずだと信じている場合、それを意地悪に変更することはできset_spamません。メソッドを与えることは、あなたがしたい最後のことです。

x*その単純なクラスであっても、との値の設定を必ずしも許可したくない場合がありyます。これが本当にクラスである場合、、などtranslateのメソッドを含めるべきではありませんrotateか?言語にレコード/構造体/名前付きタプルがないためにクラスのみである場合、これは実際にはOOの問題ではありません…</ sub>


しかし、誰も一般的なオブジェクト指向デザインを行っていません。彼らは特定の言語で設計と実装を行っています。また、一部の言語では、ゲッターとセッターが役に立たないというわけではありません。

言語にプロパティがない場合、概念的には属性であるが、実際には計算または検証されるなど、何かを表す唯一の方法は、ゲッターとセッターを使用することです。

あなたの言語に特性があるとしても、それらが不十分または不適切な場合があります。たとえば、動的アクセスのない言語でサブクラスが属性のセマンティクスを制御できるようにする場合、サブクラスは属性の代わりに計算されたプロパティを使用できません。

「後で実装を変更したい場合はどうすればよいですか?」質問(OPの質問と受け入れられた回答の両方で異なる表現で複数回繰り返されます):それが本当に純粋な実装変更であり、属性から始めた場合は、インターフェイスに影響を与えることなくプロパティに変更できます。もちろん、あなたの言語がそれをサポートしていない場合を除きます。ですから、これもまた同じケースです。

また、使用している言語(またはフレームワーク)のイディオムに従うことが重要です。美しいRubyスタイルのコードをC#で作成すると、経験豊富なC#開発者以外の開発者は、それを読むのに苦労することになります。それは悪いことです。一部の言語は、他の言語よりも慣習の周りに強い文化を持っています。そして、慣用的なゲッターのスペクトルの反対側にあるJavaとPythonが、たまたま2つの最も強い文化を持っているのは偶然ではないかもしれません。

人間の読者以外にも、規則に従うことを期待するライブラリやツールがあり、従わない場合は生活が困難になります。Interface BuilderウィジェットをObjCプロパティ以外のものに接続したり、ゲッターなしで特定のJavaモックライブラリを使用したりすると、生活がさらに困難になります。ツールがあなたにとって重要であるならば、それらと戦わないでください。

于 2014-08-19T04:47:03.940 に答える
4

オブジェクト指向設計の観点からは、どちらの方法も、クラスのカプセル化を弱めることにより、コードの保守に損害を与える可能性があります。ディスカッションについては、この優れた記事を調べることができます:http ://typicalprogrammer.com/?p=23

于 2012-04-30T18:57:11.477 に答える
4

コードは進化します。 データメンバーの保護が必要privateな場合に最適です。最終的には、すべてのクラスは、の内部を単純にねじ込むことができない、明確に定義されたインターフェイスを備えた一種の「ミニプログラム」になるはずです。

とは言うものの、ソフトウェア開発は、最初の試みで鋳鉄の彫像を押しているかのように、クラスの最終バージョンを設定することではありません。あなたがそれを使って作業している間、コードは粘土のようなものです。 あなたがそれを開発し、あなたが解決している問題領域についてもっと学ぶにつれて、それは進化します。開発中、クラスは必要以上に相互作用したり(除外する予定の依存関係)、一緒にマージしたり、分割したりする場合があります。ですから、議論は宗教的に書きたくない人々に要約されると思います

int getVar() const { return var ; }

だからあなたは持っています:

doSomething( obj->getVar() ) ;

それ以外の

doSomething( obj->var ) ;

視覚的にうるさいだけでなく、実際よりも複雑なプロセスであるgetVar()という錯覚を与えます。gettingVar()あなたが(クラスライターとして)神聖さをどのように考えるvarかは、パススルーセッターを持っている場合、クラスのユーザーにとって特に混乱します-それなら、あなたが主張するものを「保護」するためにこれらの門を設置しているように見えます、 (の神聖さvar)しかし、それでも、あなたが何をしているのかを覗き見することなく、誰もがただ入って、彼らが望むどんな価値でvarもできるという能力によって、あなたでさえその保護はあまり価値がありません。set var

したがって、私は次のようにプログラムします(「アジャイル」タイプのアプローチを想定しています。つまり、コードが何をするのか正確にわからない/精巧なウォーターフォールスタイルのインターフェイスセットを計画する時間や経験がない場合):

1)データと動作を備えた基本オブジェクトのすべてのパブリックメンバーから始めます。これが、私のすべてのC ++「サンプル」コードで、どこでもstructではなく使用していることに気付く理由です。class

2)データメンバーに対するオブジェクトの内部動作が十分に複雑になると(たとえば、std::listある種の順序で内部を保持するのが好きな場合)、アクセサー型関数が記述されます。私は自分でプログラミングしているので、常にメンバーprivateをすぐに設定するわけではありませんが、クラスの進化のどこかで、メンバーはまたはのいずれかに「昇格」しprotectedますprivate

3)完全に肉付けされ、内部について厳格な規則があるクラス(つまり、彼らが何をしているのかを正確に知っており、内部と「性交」(専門用語)しない)にはclass、デフォルトのプライベートメンバーが指定されます。選択した少数のメンバーのみが許可されますpublic

このアプローチにより、クラスの進化の初期段階で多くのデータメンバーが移行したり、移動したりするときに、そこに座ってゲッター/セッターを忠実に書くことを避けることができます。

于 2013-05-05T02:07:52.407 に答える
4

ゲッターセッターは、オブジェクト指向プログラミングの2つの基本的な側面を実装するために使用されます。

  1. 抽象化
  2. カプセル化

Employeeクラスがあるとします。

package com.highmark.productConfig.types;

public class Employee {

    private String firstName;
    private String middleName;
    private String lastName;

    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
         this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(){
        return this.getFirstName() + this.getMiddleName() +  this.getLastName();
    }
 }

ここでは、パブリック属性とは異なり、フルネームの実装の詳細はユーザーから隠されており、ユーザーが直接アクセスすることはできません。

于 2015-12-10T20:44:57.660 に答える
3

getterメソッドとsetterメソッドはアクセサーメソッドです。つまり、これらは通常、プライベートクラスのメンバーを変更するためのパブリックインターフェイスです。プロパティを定義するには、getterメソッドとsetterメソッドを使用します。getterメソッドとsetterメソッドは、クラス内でメソッドとして定義している場合でも、クラス外のプロパティとしてアクセスします。クラス外のこれらのプロパティは、クラス内のプロパティ名とは異なる名前を持つことができます。

getterメソッドとsetterメソッドを使用することには、プロパティのようにアクセスできる高度な機能を備えたメンバーを作成できるなど、いくつかの利点があります。また、読み取り専用および書き込み専用のプロパティを作成することもできます。

getterメソッドとsetterメソッドは便利ですが、他の問題の中でも特に、特定の状況でコードの保守が困難になる可能性があるため、使いすぎないように注意する必要があります。また、パブリックメンバーのように、クラス実装へのアクセスを提供します。OOPプラクティスは、クラス内のプロパティへの直接アクセスを推奨しません。

クラスを作成するときは、インスタンス変数をできるだけ多くプライベートにし、それに応じてgetterメソッドとsetterメソッドを追加することを常にお勧めします。これは、クラス内の特定の変数をユーザーに変更させたくない場合があるためです。たとえば、特定のクラス用に作成されたインスタンスの数を追跡するプライベート静的メソッドがある場合、ユーザーがコードを使用してそのカウンターを変更することは望ましくありません。コンストラクターステートメントのみが、呼び出されるたびにその変数をインクリメントする必要があります。この状況では、プライベートインスタンス変数を作成し、counter変数に対してのみgetterメソッドを許可する場合があります。つまり、ユーザーはgetterメソッドを使用することによってのみ現在の値を取得でき、新しい値を設定することはできません。セッターメソッドを使用します。

于 2012-08-30T13:02:26.650 に答える
3

プロパティの継承がないため、アクセサの使用を検討するのには十分な理由があります。次の例を参照してください。

public class TestPropertyOverride {
    public static class A {
        public int i = 0;

        public void add() {
            i++;
        }

        public int getI() {
            return i;
        }
    }

    public static class B extends A {
        public int i = 2;

        @Override
        public void add() {
            i = i + 2;
        }

        @Override
        public int getI() {
            return i;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}

出力:

0
0
4
于 2014-05-13T09:47:35.477 に答える
3

DataStructureとObjectには違いがあります。

データ構造は、動作ではなく、その内部を公開する必要があります。

オブジェクトはその内部を公開するべきではありませんが、その動作を公開する必要があります。これはデメテルの法則としても知られています。

ほとんどの場合、DTOはオブジェクトではなく、データ構造と見なされます。行動ではなく、データのみを公開する必要があります。DataStructureにSetter/Getterがあると、その中のデータではなく動作が公開されます。これにより、デメテルの法則に違反する可能性がさらに高まります。

ボブおじさんは彼の著書「クリーンコード」でデメテルの法則を説明しています。

デメテルの法則と呼ばれるよく知られたヒューリスティックがあり、モジュールは操作するオブジェクトの内部について知らないようにする必要があります。前のセクションで見たように、オブジェクトはデータを非表示にし、操作を公開します。これは、オブジェクトがその内部構造を非表示にするのではなく公開することであるため、アクセサを介してその内部構造を公開してはならないことを意味します。

より正確には、デメテルの法則は、クラスCのメソッドfは、これらのメソッドのみを呼び出す必要があると述べています。

  • C
  • fによって作成されたオブジェクト
  • fに引数として渡されるオブジェクト
  • Cのインスタンス変数に保持されているオブジェクト

このメソッドは、許可された関数のいずれかによって返されるオブジェクトのメソッドを呼び出さないでください。言い換えれば、見知らぬ人ではなく、友達と話してください。

したがって、これによると、LoD違反の例は次のとおりです。

final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

ここで、関数は、ここではctxtであるその直接の友人のメソッドを呼び出す必要があります。その直接の友人の友人のメソッドを呼び出すべきではありません。ただし、このルールはデータ構造には適用されません。したがって、ここでctxt、option、scratchDirがデータ構造である場合、内部データを何らかの動作でラップし、LoDの違反を行うのはなぜですか。

代わりに、このようなことを行うことができます。

final String outputDir = ctxt.options.scratchDir.absolutePath;

これは私たちのニーズを満たし、LoDに違反することさえありません。

ロバートC.マーチン(ボブおじさん)によるクリーンコードに触発された

于 2021-03-30T14:25:23.677 に答える
3

検証を必要とせず、状態を維持する必要さえない場合、つまり、あるプロパティが別のプロパティに依存している場合は、1つが変更されたときに状態を維持する必要があります。フィールドを公開し、ゲッターやセッターを使用しないことで、シンプルに保つことができます。

OOPは、プログラムが成長するにつれて物事を複雑にし、開発者がスケーリングするのは悪夢になると思います。

簡単な例。xmlからc++ヘッダーを生成します。ヘッダーには、検証を必要としない単純なフィールドが含まれています。しかし、それでもOOPSアクセサーはファッションであるため、次のように生成します。

const Filed& getfield() const
Field& getField() 
void setfield(const Field& field){...} 

これは非常に冗長であり、必須ではありません。シンプルな

struct 
{
   Field field;
};

十分で読みやすいです。関数型プログラミングには、データを非表示にするという概念がなく、データを変更しないため、データを必要としません。

于 2021-06-08T05:38:57.807 に答える
2

さらに、これはクラスを「将来にわたって利用できる」ようにするためのものです。特に、フィールドからプロパティへの変更はABIブレークであるため、後で「フィールドの設定/取得」以外のロジックが必要であると判断した場合は、ABIをブレークする必要があります。これは、もちろん、あらゆる問題を引き起こします。それ以外の場合は、クラスに対してすでにコンパイルされています。

于 2009-10-14T18:25:59.287 に答える
2

(プロパティをサポートする言語での)もう1つの使用法は、セッターとゲッターが操作が自明ではないことを意味する可能性があることです。通常、プロパティで計算コストがかかることは避けたいと考えています。

于 2009-10-14T18:27:45.057 に答える
2

オブジェクト指向言語では、メソッドとそのアクセス修飾子は、そのオブジェクトのインターフェースを宣言します。コンストラクターとアクセサーおよびミューテーターメソッドの間で、開発者はオブジェクトの内部状態へのアクセスを制御できます。変数が単にパブリックとして宣言されている場合、そのアクセスを規制する方法はありません。また、セッターを使用している場合は、必要な入力に対してユーザーを制限できます。その非常に変数のフィードが適切なチャネルを経由し、チャネルが事前定義されていることを意味します。したがって、セッターを使用する方が安全です。

于 2009-10-14T20:01:43.383 に答える
2

ゲッター/セッターの比較的最近の利点の1つは、タグ付き(インデックス付き)コードエディターでコードを簡単に参照できることです。たとえば、誰がメンバーを設定したかを確認したい場合は、セッターの呼び出し階層を開くことができます。

一方、メンバーが公開されている場合、ツールではメンバーへの読み取り/書き込みアクセスをフィルタリングできません。ですから、あなたはメンバーのすべての使用法を踏みにじる必要があります。

于 2017-01-03T16:10:02.227 に答える
1

アノテーションのアイデアを投げたいと思います:@getterと@setter。@getterを使用すると、obj = class.fieldは可能ですが、class.field=objはできません。@setterを使用すると、その逆も同様です。@getterと@setterを使用すると、両方を実行できるはずです。これにより、実行時に簡単なメソッドを呼び出さないため、カプセル化が維持され、時間が短縮されます。

于 2009-10-14T22:40:24.173 に答える
1

すべてを公開したくない理由の1つが考えられます。

たとえば、クラスの外部で使用することを意図していなかった変数に、チェーン変数アクセス(つまり、object.item.origin.x)を介して間接的にアクセスすることもできます。

ほとんどすべてをプライベートにし、拡張してサブクラスで参照するものだけを保護し、通常は静的なfinalオブジェクトのみをパブリックにすることで、他のプログラマーやプログラムがAPIで使用できるものとその内容を制御できます。セッターとゲッターを使用してプログラムにアクセスしたいものにアクセスしたり、アクセスできないものにアクセスしたり、コードを使用したばかりの他のプログラマーがプログラムを変更したりできます。

于 2013-12-15T20:31:28.850 に答える
1

データ隠蔽から来るゲッターとセッター。データの非表示とは、外部の人や外部の人からデータを非表示にしていることを意味します。これは、OOPの便利な機能です。

例として:

パブリック変数を作成すると、その変数にアクセスして、どこでも(任意のクラス)値を変更できます。ただし、プライベートとして作成した場合、その変数は宣言されたクラス以外のクラスで表示/アクセスできません。

publicおよびprivateはアクセス修飾子です。

では、外部でその変数にアクセスするにはどうすればよいでしょうか。

これは、ゲッターセッターの出身地です。変数をプライベートとして宣言してから、その変数のゲッターとセッターを実装できます。

例(Java):

private String name;

public String getName(){
   return this.name;
}

public void setName(String name){
   this.name= name;
}

アドバンテージ:

balance誰かが変数にアクセスしたり、値を変更/設定したりする場合は、許可が必要です。

//assume we have person1 object
//to give permission to check balance
person1.getName()

//to give permission to set balance
person1.setName()

コンストラクターで値を設定することもできますが、後で値を更新/変更するときに、setterメソッドを実装する必要があります。

于 2017-04-22T21:07:10.293 に答える
0

完成したばかりの実例を投稿したかったのです。

背景-開発中に変更するデータベースであるデータベースのマッピングを生成するために、ツールを休止状態にします。データベーススキーマを変更し、変更をプッシュしてから、休止状態ツールを実行してJavaコードを生成します。これらのマップされたエンティティにメソッドを追加するまでは、すべて問題ありません。生成されたファイルを変更すると、データベースに変更を加えるたびに上書きされます。したがって、生成されたクラスを次のように拡張します。

package com.foo.entities.custom
class User extends com.foo.entities.User{
     public Integer getSomething(){
         return super.getSomething();             
     }
     public void setSomething(Integer something){
         something+=1;
         super.setSomething(something); 
     }
}

上記で行ったことは、基本クラスに触れることなく、スーパークラスの既存のメソッドを新しい機能(something + 1)でオーバーライドすることです。1年前にクラスを作成し、基本クラスを変更せずにバージョン2に移行したい場合(悪夢のテスト)も同じシナリオです。それがお役に立てば幸いです。

于 2010-07-08T22:17:27.193 に答える
0

読み取り専用変数が必要であるが、クライアントがそれにアクセスする方法を変更する必要がない場合は、次のテンプレートクラスを試してください。

template<typename MemberOfWhichClass, typename primative>                                       
class ReadOnly {
    friend MemberOfWhichClass;
public:
    template<typename number> inline bool   operator==(const number& y) const { return x == y; } 
    template<typename number> inline number operator+ (const number& y) const { return x + y; } 
    template<typename number> inline number operator- (const number& y) const { return x - y; } 
    template<typename number> inline number operator* (const number& y) const { return x * y; }  
    template<typename number> inline number operator/ (const number& y) const { return x / y; } 
    template<typename number> inline number operator<<(const number& y) const { return x << y; }
    template<typename number> inline number operator^(const number& y) const  { return x^y; }
    template<typename number> inline number operator~() const                 { return ~x; }
    template<typename number> inline operator number() const                  { return x; }
protected:
    template<typename number> inline number operator= (const number& y) { return x = y; }       
    template<typename number> inline number operator+=(const number& y) { return x += y; }      
    template<typename number> inline number operator-=(const number& y) { return x -= y; }      
    template<typename number> inline number operator*=(const number& y) { return x *= y; }      
    template<typename number> inline number operator/=(const number& y) { return x /= y; }      
    primative x;                                                                                
};      

使用例:

class Foo {
public:
    ReadOnly<Foo, int> cantChangeMe;
};

ビット単位および単項演算子も追加する必要があることを忘れないでください!これはあなたが始めるためだけのものです

于 2014-04-01T00:46:06.613 に答える
0

ゲッター/セッターの比較的最近の利点の1つは、タグ付き(インデックス付き)コードエディターでコードを簡単に参照できることです。たとえば、誰がメンバーを設定したかを確認したい場合は、セッターの呼び出し階層を開くことができます。

一方、メンバーが公開されている場合、ツールではメンバーへの読み取り/書き込みアクセスをフィルタリングできません。ですから、あなたはメンバーのすべての使用法を踏みにじる必要があります。

于 2014-05-06T18:19:32.797 に答える
0

getterとsetterには一般的ではありませんが、これらのメソッドの使用は、AOP/プロキシパターンの使用にも使用できます。たとえば、変数の監査では、AOPを使用して任意の値の更新を監査できます。ゲッター/セッターがなければ、どこでもコードを変更する以外に不可能です。個人的には、そのためにAOPを使用したことはありませんが、ゲッター/セッターを使用するもう1つの利点があります。

于 2016-02-04T22:40:49.640 に答える
0

私の経験から、変数をプライベートとして設定し、各変数にアクセサーと修飾子を提供することが理想的です。

このようにして、要件に応じて、読み取り専用変数を作成することも、書き込み専用変数を作成することもできます。

以下の実装は、書き込み専用変数を示しています。

private String foo;
public void setFoo(String foo) { this.foo = foo; }
private String getFoo() { return foo; }

以下に読み取り専用変数を示します。

private String foo;
private void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }
于 2020-11-19T02:25:03.993 に答える
-1

私はコードにそれ自体を語らせます:

Mesh mesh = new Mesh();
BoundingVolume vol = new BoundingVolume();
mesh.boundingVolume = vol;
vol.mesh = mesh;
vol.compute(); 

あなたはそれが好きですか?セッターと一緒にここにあります:

Mesh mesh = new Mesh();
BoundingVolume vol = new BoundingVolume();
mesh.setBoundingVolume(vol);
于 2013-11-26T11:52:52.923 に答える
-2

これは良い質問であり、さらに良い答えがあります。それらはたくさんあるので、もう少しそこに置きます。この例はC#に基づいており、便利なコードです。括弧内のデータの検証については、すでに説明しました。

public class foo
{
    public int f1 { get; set; }             // A classic GS
    public int f2 { get; private set; }     // A GS with public read access, the write is only on the private level
    public int f3 { private get; set; }     // A GS where "You can set, but you can't get" outside the class
    public int f4 { get; set; } = 10;       // A GS with default value, this is a NEW feature of C# 6.0 / .NET 4.6
}
于 2015-08-22T00:58:15.757 に答える