ゲッターとセッター/アクセサーを使用する理由


1543

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

getterとsetterが単純なget / setだけではない場合、これをすぐに理解できますが、その方法は100%明確ではありません。

public String foo;

より悪い:

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

一方、前者は必要なコードが大幅に少なくなります。


6
@Dean J:他の多くの質問と重複:stackoverflow.com/search
Asaph

8
もちろん、オブジェクトがプロパティを変更する必要がない場合、どちらも同じように悪いです。すべてを非公開にし、必要に応じてゲッターを追加し、必要に応じてセッターを追加します。
Tordek、2009年

26
Googleの「アクセサは悪だ」
OMGポニー

34
機能コードや不変オブジェクトを作成している場合、「アクセサは悪」です。ステートフルな可変オブジェクトを作成している場合、それらは非常に重要です。
クリスチャンヘイター

回答:


981

実際には、クラスのフィールドを直接公開するのではなく、アクセサを使用することを検討する多くの正当な理由があります

ここに私が知っているいくつかの理由があります:

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

60
+1。追加するだけ:遅延読み込みを許可します。書き込み時にコピーを許可します。
NewbiZ 2009年

6
@bjarkef:publicアクセサメソッドはコードの重複を引き起こし、情報を公開すると思います。マーシャリング(シリアル化)にはパブリックアクセサーは必要ありません。一部の言語(Java)では、publicgetアクセサーは、依存クラスを壊さずに戻り型を変更できません。さらに、私はそれらがオブジェクト指向の原則に反するものであると信じています。次も参照してください:stackoverflow.com/a/1462424/59087
Dave Jarvis

15
@sbi:適切に設計されたフレームワークであっても、プロパティセッターを使用して購入されるものの1つは、プロパティが変更されたときにオブジェクトが別のオブジェクトに通知する機能です。
スーパーキャット2012

22
@supercat:ただし、私は一般に、公開データを宣伝していません。他のオブジェクトの通知は、パブリックデータフィールドを持つ(多かれ少なかれ)単なるデータコンテナーの重要な抽象化を提供する実際のメソッドからも同様に行うことができます。代わりplane.turnTo(dir); plane.setSpeed(spd); plane.setTargetAltitude(alt); plane.getBreaks().release();に言いたいですplane.takeOff(alt)。飛行機をtakingOffモードにするために変更する必要のある内部データフィールドは、私の心配事ではありません。また、他のどのオブジェクト(breaks)がメソッドに通知するかについても知りたくありません。
sbi 2012

8
@BenLee:私は他の言い方を本当に知りません。「アクセサ」は「ゲッター/セッター」の同義語であり、最初の2つのコメントで、「OOP」という用語の乱用である理由を説明しました。そこに到達して直接状態を操作する必要がある場合、それはその用語のOOPの意味でのオブジェクトではありません。
sbi

480

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


84
私は500kのラインアプリを必要としない場所に座って見つめています。とはいえ、一度必要になると、メンテナンスの悪夢を引き起こし始めます。チェックマークとしては十分です。
Dean J、

20
私はあなたとあなたのアプリだけがうらやましいです:-)とはいえ、それは本当にあなたのソフトウェアスタックにも依存します。たとえば、Delphi(およびC#-私はそう思いますか?)を使用すると、最初にフィールドを直接読み書きできるファーストクラスシチズンとしてプロパティを定義できます。ムチョ便利。残念ながらJavaはそうではありません-ゲッター/セッターを使用することを強制するjavabeans標準は言うまでもありません。
ChssPly76

14
これは確かにアクセサーを使用する正当な理由ですが、多くのプログラミング環境とエディターは、リファクタリングのサポートを提供し(IDEまたは無料のアドインとして)、問題の影響を多少軽減しています。
LBushkin


41
ゲッターとセッターを実装するかどうか疑問に思うときに尋ねる必要がある質問は、クラスのユーザーがクラスの内部にアクセスする必要があるのなぜですか?直接実行するか、薄い擬似レイヤーでシールドするかは問題ではありません。ユーザーが実装の詳細にアクセスする必要がある場合、それはクラスが十分な抽象化を提供していないことを示しています。このコメントも参照してください。
sbi

358

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

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

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

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

この同じ議論は、これらのパススルーゲッター/セッターペアの他の想定される利点にも適用されます。後で設定する値を変更することを決定した場合、契約を破っています。派生クラスのデフォルトの機能をオーバーライドすると、いくつかの無害な変更(ロギングやその他の監視不能な動作など)を超えて、基本クラスの規約に違反することになります。これは、OOの信条の1つと見なされているLiskov代入性原理の違反です。

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

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

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

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

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


13
正解(+1)。私の唯一の批判は、最後の段落の「検証」が最初の数件の「検証」(後者の場合は捨てたが前者では促進した)とどのように異なるかを理解するために何回か読んだことです。言葉遣いを調整することはその点で役立つかもしれません。
オービットの軽量レースは2013

14
これは素晴らしい答えですが、悲しいことに、現在の時代は「情報を隠す」とは何か、それが何のためにあるのかを忘れてしまいました。彼らは不変性について読んだり、ほとんどの俊敏性を求めて、オブジェクトの法的状態が何であるか、したがって何がそうでないかを定義するその状態遷移図を決して描きませんでした。
ダレルティーグ2013年

2
重要な観察は、ゲッターはセッターよりもはるかに有用であることです。ゲッターは計算値、またはキャッシュされた計算値を返すことができます。セッターができることは、何らかの検証とprivateフィールドの変更だけです。クラスにセッターがない場合、クラスを不変にするのは簡単です。
Raedwald 14

7
えーと、クラス不変式が何であるか、あなたは知らないと思います。それが自明でない構造である場合、それはそれが支持する不変量を持っていることを意味し、それらを考慮せずに設計することはできません。「バグがあり、1人のメンバーが間違って更新されました。」また、「メンバーの更新はクラスの不変条件に違反しました」のようなほとんどの読み取り。適切に設計されたクラスでは、クライアントコードがその不変条件に違反することはできません。
R.マルティーニョフェルナンデス

5
「ダムデータホルダーはダムデータホルダーのように見える」の+1残念ながら、最近では誰もがダムデータホルダーの周りにあるすべてのものを設計しているようで、多くのフレームワークでも必要です...
Joeri Hendrickx

93

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

たとえば、数百行のコードを調べていると、次のような問題が発生します。

person.name = "Joe";

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

ローカルのコードを一目で理解することは、読みやすさの重要な特性であり、ゲッターとセッターは壊れやすい傾向があります。だからこそ、私はできる限りそれらを避けようとし、私がそれらを使うときに彼らがすることを最小限にしようとします。


8
はい。現在、大規模なコードベースをリファクタリングしているが、これは悪夢でした。ゲッターとセッターはあまりにも多くのことを行います。たとえば、他の非常にビジーなゲッターとセッターを呼び出すと、読みやすさが低下します。検証はアクセサを使用する大きな理由ですが、アクセサを使用してそれ以上のことを行うと、潜在的なメリットがなくなるようです。
Fadecomic

31
これは、一般にセッターに対してではなく、構文糖に対しての議論です。
Phil

6
確かに真実ですが、さらに、抽象がリークする特定のオブジェクトの整合性を保証するための救済策がなく、個々のプロパティセッターが無効な状態の扉を開く理由を指摘しています。
ダレルティーグ2013年

「セッターに気付くまでは、これは美しく単純なコードの一部です」-ねえ、JavaやC#についての最初の投稿でしたか?:)
Honza Zidek 2017

読みやすさについては完全に同意します。person.name = "Joe";が呼び出されたときに何が起こっているかは完全に明示的です。情報の扱い方に問題はありません。構文の強調表示は、それがフィールドであることを示し、リファクタリングがより簡単です(2つのメソッドとフィールドをリファクタリングする必要はありません)。第2に、「getIsValid()」または「isValid()」であると考えているすべての無駄な脳サイクルを忘れることができます。ゲッター/セッターによってバグから救われたことがあるとは思えません。
ウィル

53

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

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

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

私の2セント:)


62
パブリックフィールドのすべての使用状況を突き止めることはそれほど難しくありません。それを非公開にして、コンパイラーがそれらを見つけられるようにします。
Nathan Fellman、

12
それはもちろん本当ですが、なぜそれが設計されたものよりも難しくなるのですか?get / setアプローチがより良い答えです。
Hardryv 2009年

28
@ネイサン:他の使用法を見つけることは問題ではありません。それらすべてを変更することです。
Graeme Perrow、

22
それらすべてを変更することは利点、問題ではありません@GraemePerrow :(あなたは、コードを持っていた場合の想定速度は100(あなたが契約を破った前に、それは可能性が、あなたが知っている、なぜなら!)(より高いことができることは何while(speed < 200) { do_something(); accelerate(); }
R.マルティーニョフェルナンデス

29
とても悪い例です!誰かが呼び出す必要があります:そしてmyCar.setSpeed(157);数行後にspeed = myCar.getSpeed();そして今...なぜspeed==100そうあるべきなのかを理解しようとしながらデバッグを157
楽しん

53

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

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


7
ゲッターとセッターは貧血ドメインモデルを提案します。
Raedwald 14

7
興味深い視点。しかし、ほとんどのプログラミングコンテキストで必要なのはデータ構造です。リンクされた記事の「犬」の例を取り上げます。はい、属性を設定して実際の犬の体重を変更することはできません...しかし、a new Dog()は犬ではありません。犬に関する情報を保持するオブジェクトです。そして、その使用法では、誤って記録された重量を修正できるのは当然です。
スティーブンC

3
まあ、私はあなたに、ほとんどの便利なプログラムは現実世界のオブジェクトをモデル化/シミュレーションする必要がないと言います。IMO、これはプログラミング言語に関するものではありません。それは私たちがプログラムを書くためのものです。
スティーブンC

3
現実の世界であろうとなかろうと、イゴールは完全に正しい。あなたが持っているものが本当に「構造」であり、それを名前で参照するコードを書く必要がない場合は、それをハッシュテーブルまたは他のデータ構造に入れてください。そのためのコードを記述する必要がある場合は、それをクラスのメンバーとして配置し、その変数を操作するコードを同じクラスに配置して、セッターとゲッターを省略します。PS。私は主にyegorの見解を共有していますが、コードなしの注釈付きBeanはある程度有用なデータ構造であると確信するようになりました。
ビルK

1
私はうんざりしました-この全体の答えは、正確で関連性がありますが、質問に直接対処するものではありません。おそらく、「setter / getterとpublic変数の両方が間違っている」と言うべきです...絶対に具体的に言うと、setterと書き込み可能なpublic変数は決して使用すべきではありません。しかし、どちらも他よりもはるかに優れています。
ビルK

38

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

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

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


28

あなたの言語に依存します。「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)

2
はい、私は私の答えの下のコメントで多くを言ってきました。Javaは、Pythonがプロパティを定義できる唯一の言語ではないように、getter / setterを松葉杖として使用する唯一の言語ではありません。ただし、要点はまだ残っています。「プロパティ」は同じ「パブリックフィールド」ではありません。
ChssPly76

1
@jcd-まったくありません。公開フィールドを公開することで、「インターフェース」を定義しています(ここでは、公開APIの方が適切です)。それが完了すると、後戻りはできません。プロパティはフィールドではありません。フィールドへのアクセスの試みを(定義されている場合はメソッドにルーティングすることによって)遮断するメカニズムを提供するためです。ただし、これはゲッター/セッターメソッドの構文糖衣にすぎません。これは非常に便利ですが、基礎となるパラダイムを変更しません。フィールドへのアクセスを制御できないフィールドを公開すると、カプセル化の原則に違反します。
ChssPly76

14
@ ChssPly76-同意しません。必要なときにいつでもプロパティにすることができるので、プロパティと同じようにコントロールできます。ボイラープレートゲッターとセッターを使用するプロパティとraw属性には違いがありません。ただし、メソッドを呼び出すのではなく、基礎となる言語を利用するため、raw属性の方が高速です。機能的には同じです。カプセル化に違反する可能性がある唯一の方法は、括弧(obj.set_attr('foo'))が本質的に等号(obj.attr = 'foo')より優れていると考える場合です。パブリックアクセスはパブリックアクセスです。
jcdyer

1
@jcdyerはできるだけ多くの制御を備えていますが、読みやすさはそれほどではありませんが、他にobj.attr = 'foo'何も起こらずに変数を設定するだけであると誤って想定する人もいます
Timo Huovinen

9
@TimoHuovinen obj.setAttr('foo')「何も起こらずに変数を設定するだけ」と仮定したJavaのユーザーとの違いは何ですか?それがパブリックメソッドである場合、それはパブリックメソッドです。それを使用して何らかの副作用を達成し、それがパブリックである場合、意図した副作用のみが発生したかのように機能するすべてのものに頼ることができるはずです(他のすべての実装の詳細と他の副作用、リソースの使用など) 、ユーザーの懸念から隠されています)。これはPythonでもまったく同じです。効果を達成するためのPythonの構文は単純です。
2014年

25

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


24

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

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

私が残している最後の3つ(N / AまたはD / C)...


11
「インターフェイスを設計していて、何かへの直接アクセスが問題ないかどうかわからなかった場合は、設計を続けるべきだった」というのが重要な議論だと思いますこれがゲッター/セッターの最も重要な問題です。それらはクラスを(多かれ少なかれ)パブリックフィールドの単なるコンテナーに減らします。実際の OOP、しかし、オブジェクトは、データ・フィールドの容器よりも大きいです。状態とその状態を操作するアルゴリズムをカプセル化します。このステートメントで重要なのは、状態がカプセル化され、オブジェクトによって提供されるアルゴリズムによってのみ操作されることになっているということです。
sbi 2012

22

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

少しパフォーマンステストを行いました。Integerを保持するクラス「NumberHolder」を作成しました。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万ではなく、1,000万と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万(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

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


3
単にオブジェクトのアドレスをロードしてメンバーにアクセスするためのオフセットを追加する代わりに、メモリにアクセスするための関数呼び出しを持つ「注目すべき」オーバーヘッドがあります。いずれにしても、ゲッターがフラットに最適化されたVMである可能性があります。とにかく、前述のオーバーヘッドはゲッター/セッターのすべての利点を失う価値はありません。
Alex

16

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

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

私はそれが正しいと思うか、私がアプローチが好きだという理由だけで、深い技術的ノウハウの事業主の無知を利用しません。

アクセス修飾子とビズロジックを実行することを検証するいくつかのメソッドのみを使用して、ゲッターセッターなしで記述された大規模なシステムがあります。あなたが絶対に必要な場合。何でも使ってください。


16

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

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

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


カプセル化のマントラ

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

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

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

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

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

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

int x = 1000 - 500

使用する

int x = 1000 - class_name.getValue();

素人の言葉で

「Person」クラスの表現

これの詳細を保存する必要があるとしPersonます。これにPersonは、フィールドnameageおよびがありsexます。これを行うにはnameageおよびのメソッドを作成する必要がありsexます。我々は他の人が作成する必要があれば今、それがためのメソッドを作成することが必要になりますnameagesexすべての繰り返し。

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


15

私はこれをJavaのケースについて考え直すのにかなりの時間を費やしましたが、本当の理由は次のとおりだと思います。

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

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

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


1
では、2つ目の質問です。ソースが誰にもエクスポートされないプロジェクトで、ソースを完全に制御できる場合...ゲッターとセッターで何かを得ていますか?
Dean J

2
自明ではないJavaプロジェクトでは、物事を管理可能およびテスト可能にするために、インターフェースにコーディングする必要があります(モックアップとプロキシオブジェクトを考えてください)。インターフェースを使用する場合、ゲッターとセッターが必要です。
するThorbjörnRavnアンデルセン

15

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

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

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

したがって、ゲッターによって、各子ページで何が必要かを理解する必要がなくなります。必要な場合は、getterを呼び出します。まだ取得していない場合は、getterを探しに行きます。

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

それでは、ゲッターはセッターを呼び出しますか?
icc97 2014

私が過去に行った方法のコードサンプルを追加しました-基本的に、実際のクラスを保護メンバーに格納し、その保護メンバーをgetアクセサーに返し、初期化されていない場合は初期化します。
キルブレーカー2014


13

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

  • メンバーの場合、設定と取得の両方に対して1つのアクセス仕様しかありません
  • セッターとゲッターの場合は、微調整して個別に定義できます

13

編集:私はこの質問に回答しました。プログラミングを学んでいる人々がこれを求めているので、その答えのほとんどは非常に技術的に有能ですが、初心者の場合はそれほど簡単には理解できません。私たちは皆初心者だったので、もっと初心者にやさしい答えを試してみようと思いました。

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

すごい!そして今、私たちはボトルをこれに変更します:

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をスローします。しかし、それは間違っているかもしれません。(エラー処理については有益な議論がありますが、ここでは意図的に非常に単純にしています。コメントの人々は、この単純なアプローチの欠点を指摘するでしょう。;))

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

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

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


2
私が読んだインターフェースの最初のまともな説明をありがとう、「リモートコントロール」または「車」への参照を
除外

1
「状態が変化したときにディスクに状態を書き込むボトルや、SQLデータベースに保存するボトルを用意することができます」私は非常にハードなxDをしました。しかし、とにかく、それを提示するのは素晴らしい考えです!
Xerus 2017年

10

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

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


1
Re:C#。get / setに機能を追加した場合、とにかく再コンパイルする必要はありませんか?
蒸し器25 2009年

@ steamer25:すみません、タイプミス。クラスのクライアントを再コンパイルする必要があることを意味しました。
ジョンミリキン、

5
検証ロジックをsetFooメソッドに追加するには、言語レベルでクラスのインターフェースを変更する必要はありませんが、前提条件が変更されるため、実際のインターフェースつまりコントラクトが変更されます。なぜ1は、その破壊変化としてではない治療のために、コンパイラをしたいと思うことはありますか
R.マルティーニョフェルナンデス

@ R.MartinhoFernandesこの「壊れた」問題をどのように修正するのですか?コンパイラは、壊れているかどうかを判断できません。これは、他の人のためにライブラリを作成するときにのみ問題になりますが、ここではドラゴンになるユニバーサルzOMGとして作成しています。
Phil

3
回答で述べたように、再コンパイルを要求することは、コンパイラが起こり得る重大な変更を認識できるようにする1つの方法です。そして、私が一人で作業するわけではないので、私が書くほとんどすべては、事実上「他者のためのライブラリ」です。プロジェクトの他のユーザーが使用するインターフェースを持つコードを記述します。違いは何ですか?地獄、私がそれらのインターフェースのユーザーになる場合でも、なぜ私のコードをより低い品質基準に保つ必要があるのですか?たとえ私がそれらを書いているのであっても、私は面倒なインターフェースを扱うのが好きではありません。
R.マルティーニョフェルナンデス

6

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

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


23
カプセル化ゲッターとセッターの提供は笑えるほど薄いです。こちらをご覧ください
sbi

公開インターフェースで「foo」のタイプは「T」であり、何にでも設定できると記載されている場合、それを変更することはできません。後者をタイプ 'Y'にすることも、サイズの制約などのルールを課すこともできません。したがって、多くのset / getを実行しないpublic get / setがある場合、publicフィールドが提供しないものは何も得られず、使用がより面倒になります。オブジェクトをnullに設定できるなどの制約がある場合、または値が範囲内である必要がある場合、はい、パブリックのsetメソッドが必要になりますが、この値を設定することで契約を提示できます。 t変更
thecoshman 2013年

契約が変更できないのはなぜですか?
Phil

5
契約が変更されても、物事をコンパイルし続ける必要があるのはなぜですか?
R.マルティーニョフェルナンデス

5

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

  • あなたは概念的には属性である何かを扱っていますが、
    • 言語にプロパティ(またはTclの変数トレースなどの同様のメカニズム)がない、または
    • この使用例では、言語のプロパティサポートでは不十分です。または
    • 言語の(場合によってはフレームワークの)慣用的な規則により、このユースケースのゲッターまたはセッターが推奨されます。

したがって、これがオブジェクト指向の一般的な質問になることはほとんどありません。これは言語固有の質問であり、異なる言語(および異なる使用事例)に対して異なる回答があります。


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

別の言い方をすると、クラスのコンシューマーがspam属性を持っていることさえ知らなければならないと思っている場合、属性を自由に変更することはできず、set_spamメソッドを提供することが最後に行います。

*その単純なクラスでも、xおよびy値の設定を許可したくない場合があります。これは本当にクラスであれば、それはのような方法で持つべきではないtranslaterotateなど?言語にレコード/構造体/名前付きタプルがないためクラスだけの場合、これは実際にはオブジェクト指向の問題ではありません…


しかし、誰も一般的なOO設計を行っていません。彼らは特定の言語で設計と実装を行っています。一部の言語では、ゲッターとセッターはまったく役に立たない。

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

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

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

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

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


4

オブジェクト指向の設計の観点から、クラスのカプセル化を弱めることにより、両方の選択肢がコードのメンテナンスに悪影響を与える可能性があります。ディスカッションについては、次の優れた記事をご覧ください。http//typicalprogrammer.com/?p = 23


3

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

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

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

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


3

コードは進化します。 データメンバーの保護が必要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です。

このアプローチにより、クラスの進化の初期段階で多くのデータメンバーが移行したり、移動したりする場合など、そこに座ったり、getter / setterを熱心に書いたりすることを回避できます。


1
「...の内部構造にねじ込むことができない明確に定義されたインターフェース」とセッターでの検証。
Agi Hammerthief 2014

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

3

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

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


1
何もないことを何もしないゲッターとセッターをたくさん持つのは私にとっては無意味です。getFullNameは他のことを行うため、例外です。3つの変数だけをパブリックにしてからgetFullNameを維持すると、プログラムが読みやすくなりますが、フルネームは隠されます。一般的に私はゲッターとセッターがあれば完全に問題ありません。彼らは何かユニークなことをしますおよび/またはb。あなたはたった1つしか持っていません。そうすれば、パブリックファイナルとそれ以外のすべてを行うことができます
FacelessTiger

1
これの利点は、インターフェイスを変更せずにクラスの内部を変更できることです。たとえば、3つのプロパティの代わりに、文字列の配列という1つのプロパティがあったとします。ゲッターとセッターを使用している場合は、その変更を行ってから、getter / setterを更新して、names [0]が名、names [1]がミドルネームなどであることを確認できます。ただし、パブリックプロパティを使用した場合、また、従業員がアクセスしていたすべてのクラスを変更する必要があります。これは、クラスが使用していたfirstNameプロパティが存在しないためです。
Andrew Hows 2017

1
@AndrewHows私が実際に目にしたことから、人々がクラスの内部を変更すると、インターフェースも変更され、すべてのコードの大きなリファクタリングが行われます
Eildosa

2

(プロパティをサポートする言語での)もう1つの使用法は、セッターとゲッターが操作が重要であることを意味する場合があることです。通常、プロパティで計算コストのかかる処理は行わないようにします。


ゲッターやセッターが高価な操作になるとは思いもしませんでした。そのような場合は、ファクトリーを使用するほうがよいです。必要なセッターをすべて使用してから、高価なメソッドexecuteまたはbuildメソッドを呼び出します。
Hubert Grzeskowiak 16

2

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

一方、メンバーがパブリックである場合、ツールはメンバーへの読み取り/書き込みアクセスをフィルタリングすることを可能にしません。ですから、メンバーのすべての使用法をごまかす必要があります。


あなたは正しいclicを行うことができます>ゲッター/セッターとまったく同じようにメンバーの使用法を見つける
Eildosa

2

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


1

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


2
ゲッターまたはセッターの動作を変更することは、そのとき重大な変更ではないと思います。</ sarcasm>
R.マルティーニョフェルナンデス

@ R.MartinhoFernandesは常にそうである必要はありません。TBYS
フィル

1

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


1
実行時に「簡単な方法」で実装されます。実際、おそらく簡単ではありません。
Phil

今日、これは注釈プリプロセッサで実行できます。
–ThorbjørnRavn Andersen 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.