カプセル化はデータを隠しています。ここで本当に興味深い答えをいくつか聞きたいです。
変数のprivate
セッターメソッドをすでに宣言しているときに、変数をpublic
として保持することの背後にあるポイントは何ですか?
カプセル化の使用法は理解していますが、セッターをパブリックとして公開する場合、変数をprivate
として保持することの背後にあるポイントは、public
アクセス修飾子を直接使用できます。
バックエンドでデータを保存したり管理したりする正確な方法を他の人に知られたくないからですか?
バックエンドでデータを保存または管理している正確な方法を他の人に知られたくないからですか?
はい、それがポイントです。 抽象化および情報隠蔽の概念にも関連しています。
クラスクライアントによって呼び出されたときに、文書化した効果を持つパブリックセッターを提供します。この効果が実際にどのように達成されるかは、クライアントの仕事ではありません。クラス属性の1つを変更していますか?わかりました。クライアントにそのことを知らせますが、実際に変数を変更しているという事実ではありません。将来的には、単純なバックアップ変数の代わりに、まったく異なるもの(属性のディクショナリ、外部サービス、その他)を使用し、クライアントが壊れないようにクラスを変更することができます。
したがって、セッターはabstractionであり、「このクラス属性を変更する」ためにクライアントに提供します。同時に、あなたはhidingクライアントがその事実を知る必要がないので、あなたが内部変数を使用しているという事実です。
(注:ここでは、具体的なプログラミング言語とは関係なく、一般的な概念として「属性」という単語を使用しています)
私は完全に同意します コナミマンの答え 、しかし私は一つのことを付け加えたいと思います:
あなたが本当にその抽象化を望まない場合があります。そして、それは問題ありません。
ここで使用したい簡単な例は、3次元のfloatベクトルのクラスです。
class Vector3f {
public:
float x;
float y;
float z;
};
それらのフィールドをプライベートにして、代わりにセッターを提供できますか?確かに、できます。しかし、ここでは、クラスは実際にはフロートのタプルを提供することになっているだけであり、追加の機能は必要ないと主張するかもしれません。したがって、セッターを追加するとクラスが複雑になるだけで、フィールドを公開したままにしておきます。
これで、後で噛み付く可能性のあるシナリオを簡単に構築できます。たとえば、ある日、Vector3f
sがNaN
sを格納することを許可されておらず、誰かがそうしようとすると例外をスローする必要があるという要件が発生する場合があります。しかし、そのような架空の将来の問題は、追加の抽象化を導入することを正当化するのに十分ではないはずです。
プログラマーとしてのyour呼び出しは、目前の問題にどの抽象化が意味をなすか、そしてどの抽象化が仕事を成し遂げるのを邪魔するかを決定することです。不必要な抽象化は over-engineering であり、十分に抽象化されていないのと同じくらい生産性を損ないます。
結論:誰かがそれが良い習慣だと主張したからといって、どこでも盲目的にセッターを使用しないでください。代わりに、目前の問題について考え、トレードオフを検討してください。
カプセル化により、単一のアクセスポイントを提供するためです。変数とそのセッターを次のように定義するとします。
String username;
public void setUsername(String username){
this.username = username;
}
後で、usernameプロパティを設定する前に検証を追加したいと思います。プロパティに直接アクセスしてユーザー名を10箇所に設定している場合は、単一のアクセスポイントがないため、10箇所でこの変更を行う必要があります。ただし、セッターメソッドが1つしかない場合は、1つの場所で変更を加えることで、簡単に結果を得ることができます。
Konamiman 's answer は的を射ていますが、追加したいのは、パブリックセッターの特定のケースと、あなたが求めているパブリックフィールドを直接公開する場合です。 情報隠蔽およびパブリックサーフェスからのデカップリング実装、または[〜#〜] api [〜#〜]、クラスの; 検証。
パブリックフィールドのシナリオでは、フィールドが変更されたときにフィールドの値を検証する方法はありません。パブリックセッター(_Foo {get; set;}
_プロパティまたはSetFoo(Foo value)
)メソッドの場合、検証コードを追加して必要な副作用を起動する可能性があります。これにより、クラスが常に有効または予測可能な状態。
これについて考えてみてください。私は実際のオブジェクトであるライオンをクラスで表現しています。私はこのようなことをします。
class Lion {
public int legs;
}
今、私のクラスは、オブジェクトを作成してそのレッグフィールドを設定するために他の開発者によって必要とされています。彼はこのようなことをするだろう
Lion jungleKing = new Lion();
jungleKing.legs=15;
ここで問題となるのは、Javaは、そのオブジェクトの脚の数として4を超える数を設定するように彼を制限しないということです。これはエラーではなく、問題なく実行されます。しかしそれは論理的な失敗であり、コンパイラはそこであなたを助けません。このように、ライオンはいくつもの足を持っているかもしれません。しかし、このようにコードを書くと
class Lion {
private int legs;
public void setLegs(int legs){
if(legs>4)
this.legs=4;
else this.legs=legs;
}
}
クラスのフィールドを更新するポリシーはクラス自体によって定義されているため、4つを超えるレッグを持つLionは存在しません。ポリシーを知らない人は、レッグフィールドを更新する方法がないためです。レッグフィールドを更新するには、setLegs()メソッドを使用します。このメソッドは、クラスのポリシーを認識しています。
割り当て前に範囲チェックをしたい場合はどうなりますか?それは私がセッターとゲッターを使うケースの1つです
ウィキペディアには、[ミューテーターメソッド( https://en.wikipedia.org/wiki/Mutator_method )の概要があります。これは、セッターメソッドとは何か、さまざまな言語でどのように機能するかを示しています。
短いバージョン:オブジェクトの変更時に実行される検証またはその他のロジックを導入する場合は、そのロジックを配置するセッターがあると便利です。また、保存方法を非表示にすることもできます。だから、それらはゲッター/セッターを持つ理由です。同様に、ゲッターの場合、デフォルト値またはたとえばに依存する値を提供するロジックがある場合があります。ロケール、文字エンコードなどの構成。インスタンス変数の取得または設定以外のロジックが必要になる正当な理由はたくさんあります。
明らかに、ゲッターとセッターがある場合、オブジェクトの状態を直接操作することによってそれらをバイパスすることを望まないので、インスタンス変数をプライベートに保つ必要があります。
考慮すべきその他の事項には、オブジェクトを実際に変更可能にするかどうか(そうでない場合は、フィールドをfinalにする)、オブジェクトの状態の変更をスレッドセーフにするかどうかなどがあります。ロック、同期など。
フィールドをプライベートドキュメントとして設定することは強力な事実です。これらのプライベートフィールドは、現在のクラス内でのみ直接使用されます。これは、フィールドの使用状況を追跡する必要がないため、メンテナに役立ちます。クラスを調べて、クラスの環境でのこれらのフィールドへの影響と、これらのフィールドからの影響がパブリックメソッドとプロテクトメソッドの呼び出しを経由することを確認することで、コードをより適切に推論できます。クラスの露出面を制限します。
同様に、プライベートフィールドの「セッター」を定義することは、それを再び宣伝することではありません。これは、別の強力な事実を宣言することです。このクラスに属するオブジェクトには、外部から変更できるプロパティがあります。 (用語objectおよびpropertyは、全体の境界部分の意味で使用されますおよびこの部分に関する観察可能な事実、OOPの意味ではない)
フィールドを公開するだけで十分なのに、なぜフィールドで「セッター」を宣言するのでしょうか。 宣言フィールドは、クラスのオブジェクトのプロパティに名前をバインドするだけではないため、ただし、このプロパティにメモリストレージを使用することも約束します。
したがって、「セッター付きのプライベートフィールド」を宣言する場合は、次の3つのことを宣言します。
私はあなたが決してあなたのフィールドをゲッターとセッターで無差別にプライベートにすることを提唱します。フィールドはストレージを説明するためのものです。メソッドは、環境との相互作用のためのものです。 (そして、「ゲッター」と「セッター」の特定のケースは、関心のあるプロパティを記述するためのものです)
私が実際に遭遇した多かれ少なかれ単純で現実的な例は、多くのセッターとゲッターを持つOptions
クラスです。ある時点で、他の人に依存したり、副作用がある新しいオプションを追加したい場合があります。または、オプションのグループをEnum
に置き換えます。この場合、setA
関数はa
フィールドを変更するだけでなく、いくつかの追加の構成ロジックを非表示にします。同様に、getA
はa
の値を返すだけでなく、config == cStuffSupportingA
のようなものを返します。