2

カプセル化に関するウィキペディアの記事には、次のように記載されています。

「カプセル化は、ユーザーがコンポーネントの内部データを無効または一貫性のない状態に設定するのを防ぐことにより、コンポーネントの整合性も保護します」

私はフォーラムでカプセル化に関する議論を開始しました。その中で、上記のカプセル化のルールを維持するために、常にセッターやゲッター内でオブジェクトを複製する必要があるかどうかを尋ねました。メイン オブジェクト内のオブジェクトがメイン オブジェクトの外部で改ざんされていないことを確認したい場合は、常にそれを複製する必要があると考えました。

ある討論者は、この問題では集約と構成を区別する必要があると主張しました。基本的に彼が述べていると思うのはこれです:

  • コンポジションの一部であるオブジェクト (たとえば、長方形のポイント) を返したい場合は、それを複製します。
  • 集約の一部であるオブジェクト (たとえば、UserManager の一部としてのユーザー) を返したい場合は、参照を壊さずにそれを返します。

それは私にとっても理にかなっています。しかし今、私は少し混乱しています。そして、この件についてご意見をお聞かせいただきたいと思います。

厳密に言えば、カプセル化は常にクローン作成を義務付けますか?

PS .: 私は PHP でプログラムを作成しています。PHP はスクリプト言語であるため、リソース管理はもう少し関連性があるかもしれません。

4

2 に答える 2

3

厳密に言えば、カプセル化は常にクローン作成を義務付けますか?

いいえ、違います。

あなたが言及した人は、オブジェクトの状態の保護とオブジェクトの実装の詳細の保護を混同している可能性があります。

これを覚えておいてください: カプセル化は、コードの柔軟性を高めるための手法です。適切にカプセル化されたクラスは、クライアントに影響を与えることなく実装を変更できます。これがカプセル化の本質です。

次のクラスがあるとします。

class PayRoll {
   private List<Employee> employees;

   public void addEmployee(Employee employee) {
       this.employees.add(employee);
   }
   public List<Employee> getEmployees() {
       return this.employees;
   }
}

現在、このクラスのカプセル化は低くなっています。メソッドgetEmployeesはカプセル化を破っていると言えます。これは、型 List を返すことによって、クラスのクライアントに影響を与えずにこの実装の詳細を変更することができなくなったためです。たとえば、クライアント コードに影響を与えずに Map コレクションの場合は変更できませんでした。

オブジェクトの状態を複製することで、クライアントからの予期される動作を変更する可能性があります。これは、カプセル化を解釈する有害な方法です。

public List<Employee> getEmployees() {
    return this.employees.clone();
}

addEmployee が内部 List を変更できる唯一の場所であるという意味で、上記のコードはカプセル化を改善すると言えます。したがって、新しい従業員アイテムをリストの末尾ではなく先頭に追加するという設計上の決定があるとします。私はこの変更を行うことができます:

public void addEmployee(Employee employee) {
    this.employees.insert(employee);  //note "insert" is used instead of "add"
}

ただし、それは大きな価格のカプセル化の小さな増分です. 実際にはコピーしか持っていないのに、クライアントは従業員にアクセスできるという印象を受けます。そのため、従業員 John Doe の電話番号を更新したい場合、PayRoll.getEmployees への次の呼び出しで変更が反映されることを期待して、誤って Employee オブジェクトにアクセスする可能性があります。

より高度なカプセル化による実装は、次のようになります。

class PayRoll {
   private List<Employee> employees;

   public void addEmployee(Employee employee) {
       this.employees.add(employee);
   }
   public Employee getEmployee(int position) {
       return this.employees.get(position);
   }
   public int count() {
       return this.employees.size();
   }
}

マップのリストを変更したい場合は、自由に変更できます。さらに、クライアントがおそらく期待している動作を壊しているわけではありません。PayRoll から Employee オブジェクトを変更しても、これらの変更は失われません。

あまり拡張したくありませんが、これが明確かどうか教えてください。より詳細な例に進んでいただければ幸いです。

于 2011-06-13T22:21:54.027 に答える