web-dev-qa-db-ja.com

なぜゲッターとセッター/アクセサーを使うのですか?

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

ゲッターとセッターが単なるget/set以上のことをしているのであれば、私はこれをすぐに理解することができますが、私はその方法について100%はっきりしていません:

public String foo;

より悪いです:

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

前者ははるかに少ない定型コードを取りますが。

1407
Dean J

実際には アクセサを使うことを考慮する多くの正当な理由 _カプセル化の議論だけでなく、将来の変更を容易にするのではなく_ _。

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

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

今から2週間(月、年)はあなたのセッターが単に値を設定するよりも もっと をする必要があることに気づいたとき、あなたはそのプロパティが238他のクラスで直接使われたこともわかります:-)

426
ChssPly76

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

ゲッター/セッターの組み合わせのよく言われる利点は違います。実装を変更でき、クライアントを再コンパイルする必要がないというこの主張があります。おそらく、設定者は後で検証のような機能を追加することを可能にし、あなたのクライアントはそれについて知る必要さえない。しかし、セッターに検証を追加することは、その前提条件である前の契約の違反に対する変更です。ゲッター "#:。

それで、あなたが契約を破った今、コードベースの中のすべてのファイルを変更することはあなたがしなければならない何かであり、避けることではありません。あなたがそれを避けるならば、あなたはすべてのコードがそれらのメソッドのための契約を仮定したという仮定をしています。

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

この同じ議論は、これらのパススルーgetter/setterペアの他の想定される利点にも当てはまります。後で設定される値を変更することにした場合、契約は破綻します。派生クラスのデフォルト機能を、ロギングやその他の観察不能な動作など、いくつかの無害な変更以外の方法でオーバーライドすると、基本クラスの規約に違反します。それは、オブジェクト指向の原則の1つとみなされているLiskov Substitutability Principleの違反です。

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

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

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

Client: "このクラスのオブジェクトに対して何ができますか?"
デザイナー: "いくつかの変数を読み書きできます。"
クライアント:「ああ、かっこいい、私は思う?」

ゲッターとセッターを使用する理由はありますが、それらの理由が存在しない場合は、誤ったカプセル化の神々の名前でゲッター/セッターのペアを作成するのは良いことではありません。ゲッターやセッターを作成する正当な理由には、バリデーションや異なる内部表現のように、後で変更できる可能性があるとよく言われることが含まれます。あるいは、値はクライアントによって読み取り可能であるが書き込み可能ではない(例えば、辞書のサイズの読み取り)ので、単純なゲッターが良い選択です。しかしこれらの理由はあなたが選択をするときにあるべきであり、後であなたが望むかもしれない潜在的なものとしてではありません。これはYAGNIのインスタンスです( あなたはそれを必要としないでしょう )。

331

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

何百行ものコードを調べているとします。

person.name = "Joe";

あなたがそのセッターに気づくまで、それは美しく単純にコードの一部です。さて、あなたはそのセッターをたどり、person.firstName、person.lastName、person.isHuman、person.hasReallyCommonFirstNameをセットし、そしてperson.update()を呼び出してデータベースにクエリを送信することなどを見つけました。メモリリークが発生していた場所。

一目でローカルのコードを理解することは、ゲッターとセッターが壊れる傾向がある、読みやすさの重要な特性です。そのため、可能な場合はそれらを避け、使用する場合は最小限に抑えます。

84
Kai

多くの理由があります。私が一番好きなのは、あなたが振る舞いを変えたり、変数に何を設定できるかを調整する必要があるときです。たとえば、setSpeed(int speed)メソッドがあるとしましょう。しかし、あなたはあなたがただ100の最高速度を設定することができるだけであることを望みます。

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

あなたのコードのどこかにあなたがパブリックフィールドを使っていて、あなたが上記の必要条件を必要としていることに気づいたなら、どうしますか?単にあなたのセッターを変更するのではなく、パブリックフィールドのすべての使用法を見つけ出すのを楽しんでください。

私の2セント:)

49
Peter D

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

Elegant Objects (私のオブジェクト指向プログラミングに関する本)の3.5節に、それらについての詳細があります。

48
yegor256

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

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

アクセッサやミューテータもカプセル化を可能にします - 一度設定した値をコンストラクタに設定してメソッドで使用した後に変更することを想定していない場合は、誰にも見られません。しかし、他のクラスがそれを見たり変更したりできるようにすることができれば、適切なアクセサやミューテータを提供することができます。

36
Thomas Owens

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

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)
28
jcdyer

変数やオブジェクトのカプセル化やセキュリティに必要な場合でも、実際のオブジェクト指向プログラムをコーディングしたい場合は、ACCESSORSの使用をやめてください / 、本当に必要ではないときにはしばしばそれらに依存することがあり、それは変数をpublicにするのとほとんど同じになります。

24
Jorge Aguilar

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

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

最後の3つは、(N/AまたはD/C)を離れているところです。

22
user595447

私はそれが少し遅れているのを知っています、しかし私はパフォーマンスに興味がある何人かの人々がいると思います。

私は少し性能テストをしました。私は、整数を保持するクラス "NumberHolder"を書きました。このIntegerは、getterメソッドanInstance.getNumber()を使用するか、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万と0.1万を使いました。結果:

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万(0.1万)サイクルです。

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

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

22
kangalioo

現在の配信に必要な場合以外は、ゲッターセッターを使用しないでください。変更されるものがほとんどの実動アプリケーション、システムにおける変更要求であるなら、将来何が起こるかについてあまり考えすぎないでください。

シンプルで簡単に考え、必要に応じて複雑さを増してください。

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

私はアクセス修飾子といくつかのメソッドを実行するビジネスロジックを検証するだけでゲッターセッターなしで書かれた大規模なシステムを持っています。あなたが絶対に必要な場合。何でも使う.

16
Mohamed

遅延読み込みに便利です。問題のオブジェクトがデータベースに格納されているとします。必要な場合以外は、取得したくありません。オブジェクトがgetterによって取得された場合、誰かがそれを要求するまで内部オブジェクトはnullになる可能性があります。そしてgetterへの最初の呼び出しでそれを取得することができます。

私は2、3の異なるWebサービス呼び出しからいくつかのデータをロードしている私に渡されたプロジェクトの基本ページクラスを持っていましたが、それらのWebサービス呼び出しのデータはすべての子ページで常に使用されていませんでした。 Webサービスは、すべての利点のために、 "遅い"のパイオニアの新しい定義なので、あなたがする必要がない場合は、Webサービスの呼び出しをしたくない。

私はパブリックフィールドからゲッターに移動しました、そして今ゲッターはキャッシュをチェックします、そしてそれがそこになければWebサービスを呼び出します。そのため、少し折り返しただけで、多くのWebサービス呼び出しが防止されました。

そのため、ゲッターによって、各子ページで必要なものを見つけ出す手間が省けます。私がそれを必要とするならば、私はゲッターを呼びます、そして、私がまだそれを持っていないならば、それは私のためにそれを見つけることに行きます。

    protected YourType _yourName = null;
    public YourType YourName{
      get
      {
        if (_yourName == null)
        {
          _yourName = new YourType();
          return _yourName;
        }
      }
    }
15
quillbreaker

私はJavaの場合についてこれを考えている間かなり時間を費やしました、そして、私は本当の理由が以下の通りであると信じます:

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

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

これらのメソッドは悪名高いゲッターとセッターです....

ゲッターとセッターを使います。

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

取得メソッドおよび設定メソッドは、プライベートクラスメンバにアクセスするためのパブリックインタフェースです。


カプセル化マントラ

カプセル化の要点は、フィールドを非公開にし、メソッドを公開にすることです。

取得メソッド: プライベート変数にアクセスすることができます。

設定メソッド: プライベートフィールドを変更することができます。

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

  • もっと良い
  • より安全です。そして
  • もっと早く。

値を使用できる場所ならどこでも、その値を返すメソッドを追加できます。の代わりに:

int x = 1000 - 500

つかいます

int x = 1000 - class_name.getValue();

素人の言葉で

Representation of "Person" class

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

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

14
Devrath

私はこれまでのところ答えに欠けていた1つの側面、アクセス仕様:

  • メンバーの場合、設定と取得の両方に対してアクセス指定は1つだけです。
  • セッターとゲッターのためにあなたはそれを微調整して別々に定義することができます
12
jdehaan

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

「本物の」プロパティをサポートする言語(Python、Ruby、あるいはSmalltalkなど)では、メソッドを取得または設定する意味がありません。

10
John Millikin

編集:私はこの質問をしているプログラミングを学んでいる多くの人々がいるので、私はこの質問に答えました、そして、答えの大部分は非常に技術的に有能です、しかし、あなたが初心者なら理解しにくいです。私たちはみんな初心者だったので、もっと初心者に優しい答えを試してみることにした。

2つの主なものは多態性と検証です。たとえそれがただばかげたデータ構造であっても。

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

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

その中にどれだけの量の液体があるか、そしてその容量が何ミリリットルであるかを保持する非常に単純なクラス。

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

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

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

しかし別の問題もあります。ボトルが単なる容器の一種だったらどうでしょうか。すべての容量と液体の量が満たされた複数の容器があるとしたらどうでしょうか。私たちがインターフェースを作ることができれば、残りのプログラムにそのインターフェースを受け入れさせることができ、ボトル、ジェリカン、そしてあらゆる種類のものが交換可能に機能します。それは良くないでしょうか。インターフェースはメソッドを必要とするので、これも良いことです。

次のようなものになってしまいます。

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

すばらしいです!そして今、私たちは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;
  public void setCapcityMl(int capacityMl) {
    this.capacityMl = capacityMl;
    checkNotOverFlow();
  }

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

読者への課題として、BottleOverflowExceptionの定義をお任せします。

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

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

そして、はい、それは私達が非常に単純なアイデアからすぐにもっと良い答えを得ることへ行くように思えます。

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

9
Haakon Løtveit

OO designの基本原則の1つ: カプセル化!

これには多くの利点があります。そのうちの1つは、背後でgetter/setterの実装を変更できることですが、データ型が同じである限り、その値のコンシューマは機能し続けます。

6
Justin Niessner

オブジェクト指向設計の観点からは、両方の選択肢がクラスのカプセル化を弱めることによってコードのメンテナンスに害を及ぼす可能性があります。議論のためにあなたはこの素晴らしい記事を調べることができます: http://typicalprogrammer.com/?p = 23

4
andrers52

コード進化privateは、データメンバーの保護が必要の場合に最適です。最終的に、すべてのクラスは、明確に定義されたインターフェースを持つ「ミニプログラム」のようなものである必要があります内部だけでねじ込むことはできません

つまり、ソフトウェア開発は、クラスの最終バージョンを最初の試行で鋳鉄製の彫像を押しているかのように設定することではありません。作業中は、コードは粘土に似ています。 進化する開発するにつれて、解決しようとしている問題の領域についてさらに学習します。開発中に、クラスは相互にやり取りする可能性があります(因数分解する予定の依存関係)、一緒にマージ、または分割します。だから、議論は宗教的に書きたくない人に帰着すると思う

int getVar() const { return var ; }

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

doSomething( obj->getVar() ) ;

の代わりに

doSomething( obj->var ) ;

getVar()は視覚的にうるさいだけでなく、gettingVar()が実際よりも複雑なプロセスであるという錯覚を与えます。 (クラスライターとして)varの尊厳をどのように考えるかは、クラスのユーザーがパススルーセッターを持っている場合、特に混乱を招きます。 、(varの神聖さ)しかし、あなたがvarの保護は、だれでもちょうど入ることができ、setvarが好きな値に、あなたが彼らが何をしているのか覗き見することなく、あまり価値がありません。

だから私は次のようにプログラムします(「アジャイル」タイプのアプローチを想定しています-つまり、私が知らないコードを書くときexactly何をしているのか/手の込んだウォーターフォールスタイルのインターフェースを計画する時間や経験がないセット):

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

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

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

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

3
bobobobo

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

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

Getterメソッドとsetterメソッドは便利ですが、これらのメソッドを使いすぎないように注意する必要があります。これは、特定の状況下でコードのメンテナンスが困難になる可能性があるためです。また、パブリックメンバーのように、それらはあなたのクラス実装へのアクセスを提供します。 OOPプラクティスは、クラス内のプロパティへの直接アクセスを妨げます。

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

3
Sumit Singh

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

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
3
GeZo

ゲッター および セッター は、オブジェクト指向プログラミングの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();
    }
 }

ここでは、フルネームの実装の詳細はユーザーには表示されず、public属性とは異なり、ユーザーから直接アクセスすることはできません。

2
Pritam Banerjee

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

2
Antz

もう1つの用途(プロパティをサポートする言語で)は、セッターとゲッターが操作が自明ではないことを意味することがあるということです。通常、プロパティ内で計算コストが高いものは何もしないようにします。

2
Jason Baker

ゲッター/セッターの比較的近代的な利点の1つは、タグ付き(インデックス付き)のコードエディターでコードを閲覧しやすくなることです。例えば。誰がメンバーを設定したかを知りたい場合は、設定者の呼び出し階層を開くことができます。

一方、メンバーが公開されている場合、ツールはメンバーへの読み取り/書き込みアクセスをフィルタリングすることを可能にしません。それで、あなたはメンバーのすべての用途を通さなければならない。

2
Rakesh Singh

data hidingから来るゲッターとセッター。データ隠蔽とは、私たちは部外者からデータを隠すである、または外部の人/モノがデータにアクセスできないということです。これはOOPの便利な機能です。

例として:

パブリック変数を作成すると、その変数にアクセスして値をどこでも(任意のクラス)で変更できます。しかし、あなたが非公開として作成した場合、その変数は宣言されたクラス以外のどのクラスでも/ accessを見ることができません。

publicprivateはアクセス修飾子です。

それでは、どうやってその変数に外部からアクセスすることができますか?

これはgetterssettersが来る場所です。変数をprivateとして宣言すると、その変数にgetterとsetterを実装できます。

例(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メソッドを実装する必要があります。

1
Blasanka

さらに、これはあなたのクラスを「未来に耐える」ためのものです。特に、フィールドからプロパティへの変更はABIブレークです。したがって、後で "フィールドの設定/取得"よりも多くのロジックが必要であると後で判断した場合は、ABIをブレークする必要があります。そうでなければ、すでにあなたのクラスに対してコンパイルされています。

1
Pete

アノテーションのアイデアを投げたいのですが、@ getterと@setterです。 @getterを使うと、obj = class.fieldはできるがclass.field = objはできないはずです。 @setterでは、その逆も同様です。 @getterと@setterを使えば、両方を実行できるはずです。これはカプセル化を維持し、実行時に些細なメソッドを呼び出さないことで時間を短縮します。

1
fastcodejava

私はあなたがただすべてのものを公開したくないという1つの理由を考えることができます。

例えば、あなたがクラスの外で使用することを意図していなかった変数は、チェーン変数アクセス(すなわち、object.item.Origin.x)を介して間接的にでさえも、アクセスされる可能性があります。

ほとんどすべてのものを非公開にし、サブクラスで拡張および参照する可能性があるものだけを保護対象として、一般に静的な最終オブジェクトのみをpublicにすることで、他のプログラマやプログラムがAPIで使えるものとその機能を制御できます。あなたがプログラムに欲しいものにアクセスするためにセッターとゲッターを使うことによってそれにアクセスすることができて、それができないこと、あるいは実際にあなたのコードを使用する偶然他のプログラマーはあなたのプログラムで修正できます。

1
MongooseLover

ゲッター/セッターの比較的近代的な利点の1つは、タグ付き(インデックス付き)のコードエディターでコードを閲覧しやすくなることです。例えば。誰がメンバーを設定したかを知りたい場合は、設定者の呼び出し階層を開くことができます。

一方、メンバーが公開されている場合、ツールはメンバーへの読み取り/書き込みアクセスをフィルタリングすることを可能にしません。それで、あなたはメンバーのすべての用途を通さなければならない。

0
jfritz42

Getterおよびsetterには一般的ではありませんが、これらのメソッドの使用はAOP /プロキシパターンの使用にも使用できます。たとえば、監査変数の場合は、AOPを使用して任意の値の更新を監査できます。 getter/setterがなければ、どこでもコードを変更する以外には不可能です。私はこれまでAOPを使ったことがありませんが、getter/setterを使うことのもう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);
0
spectre

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

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;
};

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

0
Jonathan

今終わったばかりの実例を投稿したいと思います。

background - データベースのマッピングを生成するためのツールを休止状態にします。データベースは、開発中に変更されます。データベーススキーマを変更し、その変更をプッシュしてから、休止状態ツールを実行して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); 
     }
}

私が上でしたことは、基本クラスに触れることなく、私の新しい機能(何か+ 1)でスーパークラスの既存のメソッドを上書きすることです。 1年前にクラスを書いていて、基本クラスを変更せずにバージョン2に進みたい場合は同じシナリオです(悪夢のテスト)。それが役立つことを願っています。

0
ebt