アソシエーション、アグリゲーション、およびコンポジションの使用は何ですか?


20

カプセル化とは何か、それを実装する3つの手法であるアソシエーション、アグリゲーション、コンポジションについて多くの理論を経験しました。

私が見つけたのは

カプセル化

カプセル化は、クラス内のフィールドをプライベートにし、パブリックメソッドを介してフィールドへのアクセスを提供する技術です。フィールドがプライベートとして宣言されている場合、クラス外の誰もアクセスできないため、クラス内のフィールドは非表示になります。このため、カプセル化はデータ隠蔽とも呼ばれます。

カプセル化は、クラス外で定義された他のコードがコードとデータにランダムにアクセスすることを防ぐ保護バリアとして説明できます。データとコードへのアクセスは、インターフェイスによって厳密に制御されます。

カプセル化の主な利点は、コードを使用する他の人のコードを壊すことなく、実装されたコードを変更できることです。この機能により、カプセル化により、コードの保守性、柔軟性、および拡張性が向上します。

協会

関連付けは、すべてのオブジェクトに独自のライフサイクルがあり、所有者がいない関係です。教師と生徒の例を見てみましょう。複数の生徒が1人の教師に関連付けられ、1人の生徒が複数の教師に関連付けられますが、オブジェクト間に所有権はなく、両方に独自のライフサイクルがあります。どちらも独立して作成および削除できます。

集計

集約は、すべてのオブジェクトに独自のライフサイクルがある特殊な形式の関連付けですが、所有権があり、子オブジェクトは別の親オブジェクトに属することはできません。学科と教師の例を見てみましょう。1人の教師を複数の部門に所属させることはできませんが、部門を削除しても教師オブジェクトは破棄されません。それは「has-a」関係と考えることができます。

組成

合成は再び集約の特殊な形式であり、これを「死」関係と呼ぶことができます。これは強力なタイプの集約です。子オブジェクトにはライフサイクルがありません。親オブジェクトを削除すると、すべての子オブジェクトも削除されます。もう一度、家と部屋の関係の例を見てみましょう。家には複数の部屋を含めることができますが、部屋の独立した生活はなく、2つの異なる家に属することはできません。家を削除すると、部屋は自動的に削除されます。

質問は:

今、これらはすべて実世界の例です。実際のクラスコードでこれらの手法を使用する方法についての説明を探しています。私が意味する、カプセル化のための3つの異なる技術を使用するためのポイントは何かこれらの技術を実装する方法どのように一度に適用される技術を選択します。


1
集約、構成、および関連付けは、カプセル化を実装するための手法ではないことに注意してください。カプセル化は、クラス/オブジェクトが1つしかない場合でも存在できます。カプセル化は、オブジェクトのデータを隠すためのオブジェクト指向の重要な機能です。
Maxood

1
「単一の教師が複数の部門に所属することはできませんリソースがコンテンツを変更したことに気づきませんでしたか?
KNU

Domain-Driven Designを行う際に、コンポジションを使用してDDD集約ルートとそのエンティティを特定することができました。古い規則の新しい使用法。
ジョン

回答:


12

あなたが説明する関連、集約、構成の区別は、昔の手動メモリ管理に遡る遺産です。たとえば、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、サービスとしてカウントを提供するカプセル化されたモジュールがあります。

NB:アクセサーを介してオブジェクトの内部状態をすべて公開することは、実際にはカプセル化の違反です。悲しいかな、それは非常に一般的な違反であり、多くの人がそれを優れたオブジェクト指向設計と混同するでしょう。


2
自動メモリ管理は、オブジェクトの関係とは関係ありません。オブジェクト図自体は、検討中のシステムの要件に従って、クラス、インターフェイス、およびメソッドをコーディングする方法をプログラマに指示します。
Maxood

2
記憶外の考慮事項もあります。データ設計またはおそらくシリアル化。構成では、RDBMSに異なる外部キー制約を設定する必要がある場合があります。または、複合子または集合子または関連オブジェクトがある場合、オブジェクトのシリアル化の処理方法を変更する必要がある場合があります。
クリス

8

カプセル化は、クラス内のフィールドをプライベートにし、パブリックメソッドを介してフィールドへのアクセスを提供する技術です。フィールドがプライベートとして宣言されている場合、クラス外の誰もアクセスできないため、クラス内のフィールドは非表示になります。このため、カプセル化はデータ隠蔽とも呼ばれます。

    public class Test{

    private String name;

       private int age;

       public int getAge(){
          return age;
       }

       public String getName(){
          return name;
       }
    }

この質問参照してください。

関連付けは、オブジェクト間の関係を示します。例:コンピューターはキーボードを入力デバイスとして使用します。

あるオブジェクトが別のオブジェクトにサービスを実行することを望む場合、関連付けが使用されます。

集約は、関連付けの特殊なケースです。オブジェクト間の方向の関連付け。オブジェクトが別のオブジェクトを「持っている」場合、それらの間に集約があります。

例:部屋にはテーブルがありますが、テーブルは部屋なしで存在できます。

    class Room {

      private Table table;

      void setTable(Table table) {
        this.table = table;
      }

    }

構成は、集計の特殊なケースです。構成はより制限的です。2つのオブジェクトの間に合成がある場合、合成されたオブジェクトは他のオブジェクトなしでは存在できません。この制限は集約されていません。例:家の部屋。家の寿命が過ぎると存在できなくなります。

    class House {

      private  Room room;

      House(Room roomSpecs) {
        room = new Room(roomSpecs);
      }

    }

コンポジションは、コードの再利用のために、継承またはオブジェクトコンポジションによって、クラスにhas-a関係を実装する設計手法です。

Javaプログラミングのベストプラクティスの1つは、継承よりも合成を使用することです


これは質問にどう答えますか?
gnat

1

通常、これらの手法を使用すると、SOLIDやさまざまなデザインパターンなどのデザイン手法が使用されます

パターンやプラクティスなどを使用するポイントは、特定の問題に対する解決策を説明することであり、これも保守可能で拡張可能です。どのパターンまたはテクニックをどこで使用するかを伝えるのに十分な経験が必要です。


1

率直に言って、学術で教えられているこれらの概念は、オブジェクト指向とクラス設計のコンテキストで重要であると感じています。これらの概念は、システムをゼロからモデリングする際に非常に役立ちます。アソシエーション、アグリゲーション、およびコンポジションは、UMLのクラス図のみに属し、メモリの問題などの技術的な制約から完全に独立しています。

さらに、モデル化するシステムのより高いレベルまたはビジネス目標も考慮する必要があります。検討中のシステムには、HouseやRoomなどのオブジェクトがありますが、(構成を介して)強く関連付けることはできません。たとえば、不動産システムをモデリングしている場合、どの部屋がどの家に属しているかを知る必要があります。しかし、特定のエリアの家の各部屋に何人の人が住んでいるかを知りたい調査または国勢調査システムをモデリングしているので、構図によって部屋を家と関連付ける必要はありません。

別の例としては、果樹園と特定の種類の果物があります。リンゴの木が植えられている場合にのみ果樹園を検討できるとしましょう。結論としては、システム全体の要件が非常に重要であるということです。

カプセル化は、オブジェクト指向設計の柱の1つです。データと、データに対して実行する操作をバンドルする必要があります。また、オブジェクトが有効な状態で存続できるようにするには、オブジェクトの特定の属性を外界から隠す必要があります。2つのオブジェクトが相互作用している場合、それらはインターフェースを介して相互作用する必要があります。そしてそれが、OOシステムを設計するときにカプセル化が保証するものです。

これらの概念がどのようにコードに適用されるかを次に示します。

ASSOCIATION: Associationは、オブジェクト間の関係を示します。プログラマーは、クラス内でどのメソッドを記述すれば相互にやり取りできるかを知ることができます。関連を理解するためのコードとクラス図の例をいくつか見つけることができます。教え、学生のあなたの例では、の関係があるの教育によって教示されています。したがって、どの学生がどの教師を持ち、どの教師がどの学生を持っているかを知ることができる一連のメソッド(技術的にはインターフェイスと呼ばれる)を記述するだけです。また、関連付けにより、システムモデラーはデータベース設計者がデータベースに保持する必要がある属性とフィールドについて支援することができます。

構成: 1つのオブジェクトが別のオブジェクトの不可欠な部分である場合、他のオブジェクトのコンストラクターでこの関係を示す必要があります。たとえば、家と部屋のシナリオでは、どの部屋がどの家タイプに属しているかを知りたい場合に備えて、次のコードを記述できます。

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

 } 

};

プログラマは、オブジェクトのデストラクタを呼び出している間、他のオブジェクトのデストラクタも呼び出されるようにします。これは非常に重要です。

集約: オブジェクト間の関係が弱い場合、プログラマーにとっては、関係を示すために代わりにインスタンス変数を使用することを意味します。そして、ミューテーター関数(セッター)を記述して、別のオブジェクトからそのオブジェクトに値を提供します。

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)
  }
}

};

1

OK、これを意味を理解して初めて意味をなす抽象的な概念ではなく、いくつかのコアプロパティにマッピングしましょう。私が受け入れられた答えに同意しない一部のコメント者のように、これらはメモリ管理とは独立した概念であると言います。

カプセル化

クライアントから複雑さを隠し、クライアントの観点から重要なものだけを公開して、クライアントが物事を簡単にすることを望みます。おまけとして、カプセル化されたコードを混乱させないという確実性が得られます。インターフェイスと機能を尊重する限り、作業をやり直すことができ、何も壊さないように安心できます。依存関係は、公開されたインターフェイスのみに依存します。

カプセル化は、オブジェクト指向の主要な柱の1つです。それはパターンではなく、原則であり、ロジックやデータにも同様に適用できます。そもそもクラスを使用することの基本的な利点にすぎず、図や設計ドキュメントで明示的に述べられているものではありません。

協会

これは基本的にオブジェクト間の依存関係のみを記述する非常に緩やかな概念です。あるオブジェクトは別のオブジェクトの存在を知っており、ある時点でその機能を使用する場合があります。図では、関連付けにより、依存関係があり、1つのオブジェクトを変更すると他のオブジェクトに影響する可能性があることが警告されます。解決すべき問題がある場合に適用する手法ではありません。それは人生の事実に似ているので、そこにあることに注意する必要があります。それは関係です。Ordersプロパティを持つ請求書のように。注文と請求書の両方に独自のライフサイクルがあります。1つは商品に関するもので、もう1つは支払いに関するもので、本質的に商品を独立させますが、どの商品が支払われているかを知ることが重要です。

封じ込め

これはシリーズに属し、集計をより有意義にするため、これを追加しています。SEの文脈でこの用語が使用されることはもうあまりありませんが、それはまだ有用だと思います。包含はカプセル化を意味しますが、厳密には包含クラス専用のオブジェクトインスタンスに関するものです。含まれるオブジェクトの機能は、パブリックインターフェイスを介して選択的に公開されます。包含クラスは、制御対象オブジェクトのライフサイクルを制御します。既存のクラスのいくつかの機能が必要なときにこれを使用して、包含クラスを機能的にします。これはXMLパーサーである可能性があり、包含クラスのクライアントはXMLに関連するものを見たり、知ったりすることはありません。隠phorとして、含まれているオブジェクトをバックオフィスワーカーと考えてください。クライアントはこれらの人々に会うことはありませんが、サービスを提供するために必要です。

集計

これは、集約されたオブジェクトのライフサイクル制御と可視性を除いて、封じ込めによく似ています。集約されたオブジェクトは、別のコンテキストですでに利用可能であり、別のエンティティによって管理されています。アグリゲーターは単に、ファサード、集約されたオブジェクトへのポータルを提供しています。クライアントが集約をアドレス指定すると、集約オブジェクト自体のインターフェースを取得しますが、その周りのラッパーは取得しません。集約のポイントは、物事の論理的なグループ化を提供することです。サービスまたはその他のラッパーオブジェクトへのアクセスポイントを考えてください。

組成

おそらく最近の起源のポピュラーな本で造られたため、これは収容のためのより現代的な用語だと思われます。包含がオブジェクト関係の技術的側面に焦点を合わせている場合、構成は通常、設計決定のコンテキストで、より具体的には継承のためのより柔軟な代替手段として使用されます。

オブジェクトの関係や所有権の性質についてはあまり言及しておらず、既存のクラスの機能を組み合わせることで機能が実装されていることを示しているだけです。したがって、他の人が行う実装の技術的な側面については何も言っていないため、このシリーズに属していないと主張します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.