私は このページ を読んでいましたが、ゲッター/セッターが正当化される時期について、OPは次のコードサンプルを提供しました。
class Fridge
{
int cheese;
void set_cheese(int _cheese) { cheese = _cheese; }
int get_cheese() { return cheese; }
}
void go_shopping(Fridge fridge)
{
fridge.set_cheese(fridge.get_cheese() + 5);
}
受け入れられる回答 は次のように述べています。
ちなみに、あなたの例では、
putCheese()
とtakeCheese()
の代わりに、クラスFridge
にget_cheese()
とset_cheese()
のメソッドを指定します。その後、まだカプセル化があります。
カプセル化は、名前をget/setからputCheese()
/takeCheese()
に変更することでどのように保存されますか?値を取得または設定しているので、単にget/setのままにしないでください。
同じ答えでそれはまた述べています:
ゲッターとセッターがあること自体はカプセル化を壊しません。カプセル化を解除するのは、何も考えずに、すべてのデータメンバー(Java lingoのすべてのフィールド)にゲッターとセッターを自動的に追加することです。
この場合、変数はcheese
のみであり、チーズを取って冷蔵庫に戻したい場合があるため、この場合の取得/設定ペアは正当化されます。
ポイントが足りないと思います。それはあなたがセッターとゲッターの名前を変更するべきであるということではなく、冷蔵庫からアイテムを追加したり削除したりするメソッドを持たせることです。すなわち
public class Fridge
{
private int numberOfCheeseSlices;
public void AddCheeseSlices(int n)
{
if(n < 0) {
throw new Exception("you cant add negative cheese!");
}
if(numberOfCheeseSlices + n > this.capacityOfFridge) {
throw new Exception("TOO MUCH CHEESE!!");
}
..etc
this.numberOfCheeseSlices += n;
}
}
これでプライベート変数がカプセル化されました。必要なだけに設定することはできません。メソッドを使用して冷蔵庫にチーズスライスを追加および削除することしかできません。これにより、必要なチーズビジネスロジックルールが確実に適用されます。
ゲッターとセッターはカプセル化を中断します毎回定義により。 議論されるかもしれないことは、時々それをする必要があるということです。それが邪魔にならないうちに、ここに私の答えがあります:
カプセル化の名前をget/setからputCheese()/ takeCheese()に変更することで、カプセル化はどのように保存されますか?
違いは意味論、つまりあなたが書くものの意味です。カプセル化は、保護だけでなく、hiding内部状態も関係します。内部状態は外部でさえ知られているべきではなく、オブジェクトはその状態を操作/使用するためのビジネス関連のメソッド(「動作」と呼ばれることもあります)を提供することが期待されます。
したがって、get
とset
は技術用語であり、「冷蔵庫」ドメインとは何の関係もないように見えますが、put
とtake
は実際には意味があるかもしれません。
ただし、put
またはtake
makeactual感覚は依然として要件に依存しており、客観的に判断することはできません。次のポイントを参照してください:
この場合、変数はチーズ1つだけなので、チーズを冷蔵庫に取り戻したい場合があるため、この場合の取得/設定ペアは正当化されます。
これは、より多くのコンテキストなしでは客観的に決定することはできません。あなたの例には、どこかにgo_shopping()
メソッドが含まれています。それがFridge
の目的である場合、それよりも必要ありませんget
またはset
が必要です、必要なのはFridge.go_shopping()
です。このようにして、要件から派生したメソッドがあり、必要なすべての「データ」はローカルであり、単に薄いのではなく実際の動作があります。ベールに包まれたデータ構造。
ジェネリックで再利用可能なFridge
を構築するのではないことを忘れないでください。 Fridge
を構築するのは、要件のみです。それを必要以上のものにするために費やしたどんな努力も、実際には無駄です。
これのほとんどすべては、カプセル化の基本的な誤解と、それがどのように適用されるかを示しています。
カプセル化を解除していた最初の応答は、間違っています。アプリケーションでは、増加/減少または追加/削除するのではなく、単に冷蔵庫でチーズの値を設定する必要がある場合があります。また、属性にアクセスしたり、属性を変更したりする必要がある場合でも、セマンティクスではありません。属性を指定しても、カプセル化は解除されません。最後に、カプセル化は、実際には「非表示」ではなく、クラスの外部で公開または操作する必要のない状態と値へのアクセスを制御すると同時に、内部で利用できるようにするタスクを実行するタスクに許可を与えることです。
値を取得または設定する正当な必要がある場合、ゲッターまたはセッターはカプセル化を解除しません。これが、メソッドを公開できる理由です。
カプセル化とは、データとそのデータを直接変更するメソッドを1つの論理的な場所であるクラスに保持することです。
この特定のケースでは、アプリケーションでチーズの値を変更する必要があることは明らかです。これがどのように行われるかに関係なく、メソッドがクラスにカプセル化されている限り、get/setまたはadd/removeを使用して、オブジェクト指向スタイルに従っています。
明確にするために、メソッド名や論理的な実行に関係なくアクセスを提供することによって、カプセル化がどのように壊れるかの例を示します。
冷蔵庫に「寿命」があるとしましょう。冷蔵庫が機能しなくなるまでの数のティックだけです(議論のために、冷蔵庫は修理できません)。論理的には、ユーザー(またはアプリケーションの残りの部分)がこの値を変更できるようにする方法はありません。プライベートにする必要があります。 「isWorking」と呼ばれる別のパブリック属性を介してのみ表示されます。有効期限が切れると、内部的に冷蔵庫はisWorkingをfalseに設定します。
ライフタイムカウントダウンの実行とisWorkingスイッチの切り替えはすべて冷蔵庫の内部で行われ、外部でプロセスに影響を与えることはできません。 isWorkingは表示のみにする必要があるため、ゲッターはカプセル化を中断しません。ただし、ライフタイムプロセスの要素にアクセサを追加すると、カプセル化が壊れます。
ほとんどの場合と同様に、カプセル化の定義はリテラルではなく、相対的です。クラス外でXを見ることができますか? Yを変更できますか?このクラスのオブジェクトに適用されるものはすべてありますか、それとも複数のクラスに機能が分散していますか?
メソッドの名前を変更するだけではありません。 2つの方法は機能が異なります。
(あなたの心の中にこれを描きなさい)
get_cheeseとset_cheeseはチーズを公開します。 putCheese()とtakeCheese()は、チーズを非表示にして管理し、ユーザーがチーズを処理する方法を提供します。観察者はチーズを見ません。彼/彼女はそれを操作する2つの方法だけを見ます。