可能性のある複製:
ゲッターとセッターを使用する理由
私はJava
に関する本を読んでおり、x
やy
などの変数のセッターとゲッターを作成するのが良いと言っています。例えば:
public int getX(){
return x;
}
public void setX(int x){
this.x = x;
}
しかし、それとの違いは何ですか
...(shape.x)... // basically getX()
そして
shape.x = 90; // basically setX()
セッターとゲッターの方が優れている場合、どのような実際的な問題が発生するか説明していただけますか?
複数の理由:
次のようなフィールドアクセスを許可する場合
shape.x = 90
その後、データを検証するためのロジックを将来追加することはできません。
xを100未満にできない場合はできないと言いますが、次のようなセッターがあれば
public void setShapeValue(int shapeValue){
if(shapeValue < 100){
//do something here like throw exception.
}
}
のような定数の
public final String SOMETHING = "SOMETHING";
それらは変更できないため、フィールドへのアクセスを許可します。たとえば、変数をゲッター、セッターで配置します。
ただし、そのような場合は、オブジェクトの参照を渡さないようにgetterメソッドで注意する必要があります(クラスにインスタンスとしてオブジェクトがある場合)。
ゲッターとセッターを使用して、任意のパッケージでプライベート変数を使用できます。
多くの人が実装の詳細をカプセル化することに言及してきましたが、それがクラスでゲッターとセッターを使用する最大の理由です。これにより、クラスを使用するすべてのコードに触れることなく、気まぐれに実装を破棄して置き換える機能など、他の多くの利点も得られます。小さなプロジェクトでは、それは大きな利点ではありませんが、コードがよく使用される(内部またはパブリック)ライブラリになった場合、huge利益。
具体的な例:数学の複素数。一部の言語には言語またはフレームワーク機能としてそれらがありますが、そうでない言語もあります。ここでは例として可変クラスを使用しますが、同じように簡単に不変にすることができます。
複素数はa + bi
の形式で実部と虚部を使用して記述でき、[gs]etRealPart
および[gs]etImaginaryPart
に適しています。
ただし、場合によっては、[gs]etRadius
(r)と[gs]etAngle
(θ)を指定して、極形式re^(iθ)
の複素数について推論する方が簡単です。
[gs]etComplexNumber(realPart, imaginaryPart)
や[gs]etComplexNumber(radius, angle)
などのメソッドを公開することもできます。引数のタイプに応じて、これらは異なる名前を必要とする場合とそうでない場合がありますが、クラスのコンシューマーは必要に応じてどちらかを使用できます。
2つの形式は交換可能です。あるクラスから別のクラスに簡単に変換できるため、クラスが内部ストレージに使用する形式は、そのクラスのコンシューマーとは無関係です。ただし、消費者はどちらの形式も使用できます。内部表現にa + biの形式を選択し、getterおよびsetterではなくフィールドを使用することを公開する場合、クラスコンシューマーに強制するだけでなく、そのフォームを使用すると、後で簡単に考えを変えて内部表現をre ^(iθ)に置き換えることもできません。これは、特定のシナリオで実装する方が簡単だからです。定義したパブリックAPIに固執しているため、具体的なフィールド名を使用して具体的な実部と虚部を公開する必要があります。
ユーザーgetterおよびsetterに対するもう1つの正当な理由は、次の例で理解できます。
public class TestGetterSetter{
private String name ;
public void setName(String name){
this.name = name ;
}
public String getName(String name){
return this.name ;
}
}
ゲッターとセッターのポイントは、取得または設定しているプライベート変数へのアクセスに使用することのみを目的としていることです。この方法でカプセル化を行うと、後でコードをリファクタリングまたは変更するのがはるかに簡単になります。
そのゲッターの代わりに名前を使用すると想像してください。デフォルトのようなものを追加したい場合(以前に設定されていなかった場合、デフォルトの名前は「ゲスト」です)、ゲッターとsayName関数の両方を変更する必要があります。
public class TestGetterSetter{
private String name ;
public void setName(String name){
this.name = name ;
}
public String getName(String name){
if (this.name == null ){
setName("Guest");
}
return this.name ;
}
}
Getterおよびsetterをgetおよびsetで開始する必要はありません。これらは通常のメンバー関数です。ただし、それは慣例です。 (特にJava Beansを使用する場合)
ゲッターとセッターについて考えることができる最良の理由の1つは、クラスのAPIの永続性です。 pythonなどの言語では、名前でメンバーにアクセスし、後でメソッドに切り替えることができます。関数は、プロパティであるJavaにアクセスすると、それとは異なる動作をするためです。スコープを後で制限すると、クライアントが破損します。
ゲッターとセッターを提供することにより、プログラマーは、パブリックAPIで記述された契約を遵守する限り、メンバーと動作を自由に変更できる柔軟性を備えています。
仮に、自分のクラス(YourClass)で行ってきたことをよりうまく処理できるライブラリを見つけたとします。この時点で行うべき自然なことは、YourClassをそのライブラリのラッパーインターフェイスにすることです。クライアントコードを取得または設定する必要のある「X」という概念がまだあります。当然、この時点で、アクセサー関数を作成する必要があります。
アクセサー関数の使用を怠り、クライアントコードがYourClass.xに直接アクセスできるようにした場合、YourClass.xに触れたすべてのクライアントコードを書き換える必要があります。ただし、最初からYourClass.getX()およびYourClass.setX()を使用していた場合は、YourClassを書き換えるだけで済みます。
プログラミング、特にオブジェクト指向プログラミングの重要な概念の1つは、実装の詳細を非表示にして、他のクラスまたはモジュールのコードで直接使用されないようにすることです。この方法では、実装の詳細を変更した場合(上記の例のように)、クライアントコードはその違いを認識せず、変更する必要がありません。クライアントコードが知っているすべての場合、「x」は変数であるか、オンザフライで計算される値である可能性があります。
これは単純化しすぎており、実装を隠すことが有益なすべてのシナリオを網羅しているわけではありませんが、最も明らかな例です。実装の詳細を隠すという概念は、現在OOPと非常に強く結びついていますが、OOPが考案される数十年前にさかのぼる議論を見つけることができます。それは、ソフトウェア開発の中心概念の1つに戻ります。これは、大きな曖昧な問題を取り上げ、それを簡単に解決できる小さな明確な問題に分割することです。アクセサー関数は、小さなサブタスクを分離し、明確に定義するのに役立ちます。クラスが互いの内部構造について知っているほど、より良いものになります。
元々、ゲッター/セッターパターンは、encapsulating
の外部class
からのinterface
の内部によって、優れたオブジェクト指向設計を促進するために作成されました。
これがあなたの質問のベストアンサーです なぜゲッターとセッターを使用するのですか?
答えに入る前に、事前に何かを知るべきです...! "JavaBeans"。
JavaBeansは、プロパティを持つJavaクラスです。私たちの目的では、プロパティをプライベートインスタンス変数と考えてください。それらはプライベートであるため、クラスの外部からアクセスできる唯一の方法は、クラス内の「メソッド」を使用することです。
プロパティの値を変更するメソッドはsetterメソッドと呼ばれ、プロパティの値を取得するメソッドはgetterメソッドと呼ばれます。
理由はたくさんあります。ここにほんの一部があります。
ゲッター/セッターもパブリックメンバーもオブジェクト指向設計ではありません。どちらも、おそらく最初にオブジェクトのプロパティにアクセスするべきではない世界にオブジェクトデータを公開することにより、OOPカプセル化を解除します。
これは、OOPの原則 encapsulation を適用することにより行われます。
オブジェクトの一部のコンポーネントへのアクセスを制限するための言語メカニズム。
つまり、クラスの属性とメソッドの可視性を定義する必要があります。 3つの一般的な可視性があります。
プライベート/保護された属性を宣言するとき、値を取得(get)および値を変更(set)するメソッドを作成することをお勧めします。可視性に関する1つの例は、[ArrayList][2]
クラスです。内部配列の実際のサイズを知るためのsize
プロパティがあります。クラスmustのみがその値を変更するため、コードは次のようになります
public class ArrayList<E> {
private int size;
private Object[] array;
public getSize() {
return this.size;
}
public void add(E element) {
//logic to add the element in the array...
this.size++;
}
}
この例では、サイズの値はクラスメソッド内でのみ変更でき、コードで呼び出すことで実際のサイズを取得できることがわかります(変更しないでください)。
public void someMethod() {
List<String> ls = new ArrayList<String>();
//adding values
ls.add("Hello");
ls.add("World");
for(int i = 0; i < ls.size(); i++) {
System.out.println(ls.get(i));
}
}
ゲッターとセッターは、パブリックメソッドを通じてのみアクセスできるようにすることでクラスのフィールドをカプセル化し、値自体をプライベートに保ちます。それは良いOO原則と考えられています。
確かに、値を設定するか返すだけである場合、多くの場合、冗長なコードのように見えます。ただし、セッターを使用すると、入力の検証またはクリーンアップを行うこともできます。これを1か所にまとめると、オブジェクトのデータの整合性が向上し、
オブジェクト指向プログラミング言語を使用しているためです。ここでは、データの非表示とカプセル化を使用しています。変数は、外部から直接アクセスできないようにする必要があります(データの非表示を実現するため)。
shape.x
正しくありません。ゲッターおよびセッターメソッドは、カプセル化を実現する方法であるxの値を取得および設定するために使用されます。