今日、私は本を読みましたが、その著者は、適切に設計されたクラスでは、属性にアクセスする唯一の方法はそのクラス メソッドの 1 つを使用することだと書いています。それは広く受け入れられている考えですか?属性をカプセル化することがなぜそれほど重要なのでしょうか? それをしないと、どのような結果が生じる可能性がありますか? これによりセキュリティが向上するなどのことを以前どこかで読みました。PHP または Java の例は非常に役に立ちます。
6 に答える
それは広く受け入れられている考えですか?
オブジェクト指向の世界では、そうです。
属性をカプセル化することがなぜそれほど重要なのでしょうか? それをしないと、どのような結果が生じる可能性がありますか?
オブジェクトは、他のオブジェクトがパブリック インターフェイスを介して制御された方法でアクセスできるデータと動作を含むまとまりのあるエンティティであることを目的としています。クラスがそのデータと動作をカプセル化しない場合、アクセスされるデータを制御できなくなり、パブリック インターフェイスによって暗示された他のオブジェクトとのコントラクトを実行できなくなります。
これに関する大きな問題の 1 つは、クラスを内部的に変更する必要がある場合、パブリック インターフェイスを変更する必要がないことです。そうすれば、コードが壊れることはなく、他のクラスは以前と同じように使用し続けることができます。
PHP または Java の例は非常に役に立ちます。
Java の例を次に示します。
public class MyClass {
// Should not be < 0
public int importantValue;
...
public void setImportantValue(int newValue) {
if (newValue < 0) {
throw new IllegalArgumentException("value cannot be < 0");
}
}
...
}
ここでの問題は、パブリックにするのではなくカプセル化していないimportantValue
ためprivate
、オブジェクトが無効な状態になるのを防ぐために、セッターに設定したチェックをだれでも回避できることです。importantValue
0 未満であってはなりませんが、カプセル化されていないため、0 未満になるのを防ぐことはできません。
それをしないと、どのような結果が生じる可能性がありますか?
カプセル化の背後にある全体的な考え方は、クラスに関連するすべての知識 (インターフェース以外) はすべてクラス自体の中にあるということです。たとえば、属性への直接アクセスを許可すると、割り当てを行うコードで割り当てが有効であることを確認する責任が生じます。有効なものの定義が変更された場合は、クラスを使用してすべてを調べて監査し、それらが準拠していることを確認する必要があります。ルールを「セッター」メソッドにカプセル化するということは、ルールを 1 か所だけ変更する必要があることを意味し、面白いことをしようとしている呼び出し元は、代わりに例外がスローされる可能性があります。属性が変更されたときに実行したいことは他にもたくさんありますが、setter はそれを実行する場所です。
属性をバインドする規則がない (たとえば、整数に収まるものであれば何でもよい) 属性への直接アクセスを許可するかどうかは、議論の余地があります。ゲッターとセッターを使用することは、一貫性を保つために良い考えだと思います。つまり、属性を直接変更できるかどうかを調べなくても、呼び出して属性setFoo()
を変更できることが常にわかっているのです。foo
また、クラスの将来性を保証することもできるため、実行する追加のコードがある場合は、それを配置する場所が既に存在します。
個人的には、ゲッターとセッターを使わなければならないのは不器用に見えると思います。x.foo = 34
割り当ての前、後、または割り当ての代わりに起動するコードを定義できるメンバーのデータベース トリガーに相当する言語がx.setFoo(34)
登場する日を楽しみにしています 。
オブジェクトオリエンテプログラミングには、(http://en.wikipedia.org/wiki/Open/closed_principle)として知られている原則があります:POC->オープンとクローズの原則。この原則は次のとおりです。拡張性(継承)のためにウェルクラスの設計を開く必要がありますが、内部メンバーの変更(カプセル化)のために閉じる必要があります。これは、オブジェクトの状態を気にせずに変更できないことを意味します。
したがって、新しい言語は、プロパティ(C ++またはJavaのgettersおよびsettersメソッド)を介して内部変数(フィールド)のみを変更します。C#では、プロパティはMSILのメソッドにコンパイルされます。
C#:
int _myproperty = 0;
public int MyProperty
{
get { return _myproperty; }
set { if (_someVarieble = someConstantValue) { _myproperty = value; } else { _myproperty = _someOtherValue; } }
}
C ++ / Java:
int _myproperty = 0;
public void setMyProperty(int value)
{
if (value = someConstantValue) { _myproperty = value; } else { _myproperty = _someOtherValue; }
}
public int getMyProperty()
{
return _myproperty;
}
「優れた OOD」がどのように達成されるかについての意見は十数個あります。また、非常に経験豊富なプログラマーやデザイナーは、デザインの選択や哲学について意見が分かれる傾向があります。さまざまな言語背景とパラダイムを持つ人々に尋ねると、これは炎上戦争のきっかけになる可能性があります。
はい、理論上は理論と実践は同じであるため、言語の選択が高レベルの設計に大きく影響することはありません。しかし、実際にはそうであり、そのために良いことも悪いことも起こります。
これを追加させてください:それは依存します。カプセル化 (サポート言語による) により、クラスの使用方法をある程度制御できるため、人々に「これは API であり、これを使用する必要がある」と伝えることができます。他の言語 (Python など) では、公式の API と非公式 (変更される可能性があります) のインターフェイスの違いは、命名規則のみです (結局、ここではすべての大人が同意しています) 。
カプセル化はセキュリティ機能ではありません。
考えるべきもう一つの考え
アクセサーでカプセル化すると、将来の保守性も大幅に向上します。上記のFeanorの回答では、セキュリティチェックを実施するのにうまく機能しますが(instvarがプライベートであると仮定)、さらに多くのメリットがあります。
次のシナリオを考えてみましょう:
1) アプリケーションを完成させ、一部のユーザー (内部、外部など) に配布します。
2) BigCustomerA があなたのチームに連絡し、製品に監査証跡を追加することを望んでいます。
誰もが自分のコードでアクセサ メソッドを使用している場合、これを実装するのはほとんど簡単になります。そのようなもの:
MyAPI バージョン 1.0
public class MyClass {
private int importantValue;
...
public void setImportantValue(int newValue) {
if (newValue < 0) {
throw new IllegalArgumentException("value cannot be < 0");
}
importantValue = newValue;
}
...
}
MyAPI V1.1 (監査証跡付き)
public class MyClass {
private int importantValue;
...
public void setImportantValue(int newValue) {
if (newValue < 0) {
throw new IllegalArgumentException("value cannot be < 0");
}
this.addAuditTrail("importantValue", importantValue, newValue);
importantValue = newValue;
}
...
}
API の既存のユーザーはコードを変更せず、新しい機能 (監査証跡) を利用できるようになりました。
アクセサーを使用したカプセル化がなければ、膨大な移行作業に直面します。
初めてコーディングするときは、大変な作業に思えます。入力する方がはるかに高速です: class.varName = something
vs class.setVarName(something);
しかし、誰もが簡単な方法をとった場合、BigCustomerA の機能要求に対して支払いを受けるのは大変な労力になります。
論文のアイデアを取り上げます(Head First C#から):
- フィールドがどのように悪用される可能性があるかを考えてください。それらが適切に設定されていない場合、何が問題になる可能性があります。
- クラスのすべてが公開されていますか? カプセル化について少し考えてみてください。
- 処理または計算が必要なフィールドは? 彼らは最有力候補です。
- 必要な場合にのみ、フィールドとメソッドを公開してください。何かを公に宣言する理由がない場合は、そうしないでください。