カプセル化とは何か、それを実装するための3つの手法である関連、集約、構成について、多くの理論を検討してきました。
カプセル化は、クラスのフィールドをプライベートにして、パブリックメソッドを介してフィールドへのアクセスを提供する手法です。フィールドがプライベートとして宣言されている場合、クラス外のユーザーはそのフィールドにアクセスできないため、クラス内のフィールドは非表示になります。このため、カプセル化はデータ非表示とも呼ばれます。
カプセル化は、クラスの外部で定義された他のコードによってコードとデータがランダムにアクセスされるのを防ぐ保護バリアとして説明できます。データとコードへのアクセスは、インターフェースによって厳しく制御されます。
カプセル化の主な利点は、コードを使用する他のユーザーのコードを壊すことなく、実装されたコードを変更できることです。この機能により、カプセル化により、コードの保守性、柔軟性、拡張性が向上します。
関連付けは、すべてのオブジェクトに独自のライフサイクルがあり、所有者がいない関係です。教師と生徒の例を見てみましょう。複数の生徒は1人の教師と関連付けることができ、1人の生徒は複数の教師と関連付けることができますが、オブジェクト間に所有権はなく、両方に独自のライフサイクルがあります。どちらも個別に作成および削除できます。
集計は、すべてのオブジェクトに独自のライフサイクルがあるアソシエーションの特殊な形式ですが、所有権があり、子オブジェクトは別の親オブジェクトに属することができません。学科と教師の例を見てみましょう。 1人の教師が複数の部門に所属することはできませんが、部門を削除しても、教師オブジェクトは破棄されません。それは「ハサミ」関係と考えることができます。
合成もまた、集約の特殊な形式であり、これを「死」関係と呼ぶことができます。これは集約の強力なタイプです。子オブジェクトにはライフサイクルがなく、親オブジェクトが削除されるとすべての子オブジェクトも削除されます。ハウスと部屋の関係の例をもう一度見てみましょう。家は複数の部屋を含むことができますが、部屋の独立した生活はなく、どの部屋も2つの異なる家に属することはできません。家を削除すると、部屋は自動的に削除されます。
質問は:
これらはすべて実際の例です。実際のクラスコードでこれらの手法を使用する方法についての説明を探しています。 カプセル化に3つの異なる手法を使用することのポイントは何ですか、これらの手法を実装する方法および方法時間に適用できるテクニックを選択する。
アソシエーション、アグリゲーション、コンポジションの違いは、説明したとおり、昔ながらの手動のメモリ管理に遡る遺産です。たとえばC++では、オブジェクトが使用するメモリを手動で解放する必要があるため、構成されたオブジェクトのライフサイクルを注意深く設計することが最も重要です。集約と構成の違いはまだ多くの教科書で教えられていますが、自動メモリ管理のある環境でプログラミングする場合は本質的に無関係です。あなたがガベージコレクションを持っている場合、それらのすべては単なる構成、期間です。
一方、カプセル化は、あなたが説明するよりもはるかに一般的な原則です。それは何よりもまず、データとこのデータを操作する関数を1つのモジュールにバンドルするという考えです。これを実装する1つの方法は、モジュールの状態をプライベートに保ち、パブリックサービスを通じてその状態への変更を公開することです。したがって、クライアントは自分で状態にアクセスすることはできませんが、メッセージを送信することによってモジュールに意図を伝える必要があります。したがって、カプセル化はオブジェクトに限定されず、サービスにも適用されます。実際、オブジェクトを見る1つの方法は、オブジェクトをサービスとして見ることです。
これはカプセル化の例です
public class Counter {
private int n = 0;
public int inc() { return n++; }
}
またはラムダ関数を使用して同じ
var counter = (function() {
var n = 0;
var inc = function() { return n++; }
return inc;
})();
どちらの場合も、データ、つまり変数n
は、データを操作する関数inc
と一緒にバンドルされます。また、他の関数がn
にアクセスすることはできません。そのため、カウントをサービスとして提供するカプセル化されたモジュールがあります。
注意:アクセサーを通じてオブジェクトの内部状態をすべて公開することは、実際にはカプセル化違反です。悲しいかな、それは多くの人がそれを優れたオブジェクト指向設計と混同するほどの一般的な違反です。
カプセル化は、クラスのフィールドをプライベートにして、パブリックメソッドを介してフィールドへのアクセスを提供する手法です。フィールドがプライベートとして宣言されている場合、クラス外のユーザーはそのフィールドにアクセスできないため、クラス内のフィールドは非表示になります。このため、カプセル化はデータ非表示とも呼ばれます。
public class Test{
private String name;
private int age;
public int getAge(){
return age;
}
public String getName(){
return name;
}
}
この質問を参照してください または 。
Associationは、オブジェクト間の関係を示します。例:コンピューターはキーボードを入力デバイスとして使用します。
関連付けは、あるオブジェクトが別のオブジェクトにサービスを実行させたいときに使用します。
Aggregationは、関連付けの特殊なケースです。オブジェクト間の方向の関連付け。オブジェクトが別のオブジェクトを「持っている」場合は、それらのオブジェクトの間に集約があります。
例:部屋にはテーブルがありますが、テーブルは部屋なしでも存在できます。
class Room {
private Table table;
void setTable(Table table) {
this.table = table;
}
}
Compositionは、集計の特殊なケースです。構成はより制限的です。 2つのオブジェクトの間に合成がある場合、合成されたオブジェクトは他のオブジェクトなしでは存在できません。この制限は集約にはありません。例:家の部屋。家の寿命が過ぎると存在できなくなります。
class House {
private Room room;
House(Room roomSpecs) {
room = new Room(roomSpecs);
}
}
構成は、継承またはコード再利用のためのオブジェクト構成によって、クラスに関係を実装する設計手法です。
Javaプログラミングのベストプラクティスの1つは、継承よりも構成を使用することです。
率直に言って、これらの学問で教えられている概念は、オブジェクト指向とクラス設計のコンテキストで重要であると感じています。これらの概念は、システムを最初からモデリングする場合に非常に役立ちます。アソシエーション、アグリゲーション、およびコンポジションは、UMLのクラス図に排他的に属し、メモリの問題などのテクノロジーの制約から完全に独立しています。
さらに、モデル化するシステムの上位レベルまたはビジネス目標も考慮する必要があります。検討中のシステムにはHouseやRoomのようなオブジェクトがありますが、(構成を介して)強く関連させることはできません。たとえば、不動産システムをモデリングしている場合、どの部屋がどの家に属しているかを知る必要があるかもしれません。しかし、特定のエリアの家の各部屋に何人の人が住んでいるかを知りたい測量システムまたは国勢調査システムをモデル化している場合、構成を介して部屋と家を関連付ける必要はありません。
別の例としては、果樹園とある種の果物があります。果樹園は、Apple木が植えられている場合にのみ考慮できるとしましょう。システム全体の要件は非常に重要です。
カプセル化はオブジェクト指向設計の柱の1つです。データとデータに対して実行する操作をバンドルする必要があります。また、オブジェクトが有効な状態で存続できるようにするには、オブジェクトの特定の属性を外界から隠す必要があります。 2つのオブジェクトが相互作用する場合、それらはインターフェースを介して互いに相互作用する必要があります。そして、それがOOシステムを設計するときにカプセル化が保証するものです。
これらの概念をコードに適用する方法を次に示します。
ASSOCIATION:関連付けは、オブジェクト間の関係を示します。これにより、プログラマーは、クラスを相互に対話させるためにクラスに書き込むメソッドを知ることができます。関連付けを理解するために、コードとクラス図のいくつかの例を見つけることができます。 Teach and Studentの例では、teachingとtaught byの関係があります。したがって、単純に一連のメソッド(技術的にはインターフェイスと呼ばれます)を記述して、どの生徒がどの教師を、どの教師がどの生徒を持っているかを知ることができます。また、関連付けにより、システムモデラーは、データベースに保持する必要のある属性とフィールドについてデータベース設計者を支援できます。
COMPOSITION:あるオブジェクトが別のオブジェクトの不可欠な部分である場合、他のオブジェクトのコンストラクターでこの関係を示す必要があるかもしれません。たとえば、家と部屋のシナリオでは、どの部屋がどの家タイプに属しているかを知りたい場合に備えて、次のコードを記述できます。
class House{
string _HouseType;
public:
void setHouseType(string house_type)
{
this. _HouseType = house_type;
}
string getHouseType()
{
return _HouseType;
}
};
House HouseObject = new House();
class Room{
public:
Room(string HouseType) {
this._HouseType = HouseObject.getHouseType(); //as in my system a room cannot exist without a house
}
};
プログラマーは、オブジェクトのdestructorsを呼び出すときに、他のオブジェクトのデストラクタも呼び出されることを確認します。これは非常に重要です。
AGGREGATION:オブジェクト間の関係が弱い場合、プログラマーにとっては、関係を示すために代わりにインスタンス変数を使用することになります。次に、ミューテーター関数(セッター)を記述して、別のオブジェクトからそのオブジェクトに値を提供します。
class Department{
string dept_name;
public:
void setDeptName(string name)
{
this.dept_name=name;
}
string getDeptName()
{
return dept_name;
}
};
Department DepartmentObject = new Department();
class Teacher{
string dept_name;
public:
setDeptName(string name)
{
this.dept_name = DepartmentObject.getDeptName(); //You only need to invoje this method when needed (aggregation)
}
}
};
これらの手法を使用すると、通常、 [〜#〜] solid [〜#〜] またはさまざまな 設計パターン のような設計手法になります。
パターン、プラクティスなどを使用するポイントは、保守可能で拡張可能な特定の問題の解決策を説明することです。必要なのは、どのパターンまたは手法をどこで使用するかを指示するのに十分な経験を積むことだけです。
OK、これを、それらが何を意味するかを理解して初めて意味を持つ抽象的な概念ではなく、いくつかのコアプロパティにマッピングしましょう。一部のコメンターのように、私は受け入れられた回答に同意しませんが、これらはメモリ管理とは独立した概念であると私は言います。
カプセル化
クライアントから複雑さを隠し、クライアントの観点から重要なものだけを公開して、クライアントにとってより簡単にしたいとします。おまけとして、カプセル化されたコードを混乱させることができないという確実性が得られます。インターフェースと機能性を尊重している限り、何かをやり直すことができ、何も壊さないので安心できます。依存関係は公開されたインターフェースのみに依存します。
カプセル化は、オブジェクト指向の主要な柱の1つです。これはパターンではなく、原則であり、ロジックとデータの両方に適用できます。これは、そもそもクラスを使用することの基本的な利点にすぎず、図や設計ドキュメントで明示的に述べられているものとは異なります。
関連付け
これは非常に緩い概念であり、基本的にオブジェクト間の依存関係のみを説明します。あるオブジェクトは別のオブジェクトの存在を認識しており、ある時点でその機能を使用する場合があります。図では、関連付けにより、依存関係があり、1つのオブジェクトを変更すると他のオブジェクトに影響を与える可能性があることが警告されます。解決すべき問題があるときに適用する手法ではありません。それは、そこにいるときに注意する必要がある現実の事実に似ています。それは関係です。 Ordersプロパティを持つ請求書のように。注文と請求書の両方に独自のライフサイクルがあります。 1つは商品に関するもので、もう1つは支払いに関するものです。これにより、それらは本質的に独立しますが、どの商品が支払われるのかを知ることが重要です。
封じ込め
これはシリーズに属し、集計をより意味のあるものにするため、これを追加します。 SEのコンテキストで使用されている用語はもうあまり聞こえませんが、それでも有用だと思います。包含はカプセル化を意味しますが、厳密には包含クラスにプライベートなオブジェクトインスタンスについてです。含まれるオブジェクトの機能は、パブリックインターフェイスを介して選択的に公開されます。包含クラスは、制御対象オブジェクトのライフサイクルを制御します。包含クラスを機能させるために既存のクラスのいくつかの機能が必要な場合に、これを使用します。これはXMLパーサーである可能性があり、包含クラスのクライアントは、XMLに関連するものを決して見たり、知ったりすることはありません。隠喩として、含まれているオブジェクトをバックオフィスワーカーと考えてください。クライアントはこれらの人々に会うことはありませんが、サービスを提供するために必要です。
集計
これは、ライフサイクル制御と集約されたオブジェクトの可視性を除いて、コンテインメントによく似ています。集約されたオブジェクトは、すでに別のコンテキストで利用可能であり、別のエンティティによって管理されています。アグリゲーターは、ファサード、集約されたオブジェクトへのポータルを提供するだけです。クライアントがアグリゲートをアドレス指定すると、クライアントは、そのラッパーではなく、アグリゲートオブジェクト自体のインターフェースを取得します。集合体のポイントは、物事の論理的なグループ化を提供することです。サービスまたは他のラッパーオブジェクトへのアクセスポイントを考えてください。
構成
これは、比較的最近のOriginの人気のある本で作成されたためか、おそらくこれは封じ込めのより現代的な用語のようです。封じ込めがオブジェクト関係の技術的側面に焦点を当てている場合、構成は通常、設計決定のコンテキストで、より具体的には継承のより柔軟な代替手段として使用されます。
オブジェクトの関係や所有権の性質についてはあまり触れておらず、既存のクラスの機能を組み合わせて機能が実装されていることを示しているだけです。したがって、他の人が行っている実装の技術的な側面については何も述べていないため、このシリーズには属していないと私は主張します。