487

关联、聚合和组合之间有什么区别?请在执行方面进行说明。

4

20 回答 20

514

对于两个对象,Foo可以Bar定义关系

关联- 我与一个对象有关系。 Foo用途Bar

public class Foo {         
    private Bar bar;
};

注意:请参阅Fowler 的定义- 关键是它Bar在语义上与依赖关系相关,Foo而不仅仅是依赖关系(如intor string)。

构图- 我拥有一个对象,我对它的生命周期负责。什么时候Foo死,什么时候死Bar

public class Foo {
    private Bar bar = new Bar(); 
}

聚合- 我有一个从别人那里借来的对象。Foo死了,还能Bar活下去。

public class Foo { 
    private Bar bar; 
    Foo(Bar bar) { 
       this.bar = bar; 
    }
}
于 2012-05-01T07:20:07.167 回答
165

我知道这个问题被标记为 C#,但这些概念是非常通用的问题,比如这里的重定向。所以我将在这里提供我的观点(从我更舒服的java角度来看有点偏颇)。

当我们想到面向对象的本质时,我们总是想到对象、类(对象蓝图)以及它们之间的关系。对象通过方法相互关联和交互。换句话说,一个类的对象可以使用由另一个类的对象提供的服务/方法。这种关系称为关联。.

聚合和组合是关联的子集,这意味着它们是关联的特定情况。

在此处输入图像描述

  • 在一个类的聚合和组合对象中“拥有”另一个类的对象
  • 但是有一个细微的差别。在组合中,由其所属类的对象所拥有的类的对象不能独立生存(也称为“死亡关系”)。它将始终作为其拥有对象的一部分存在,而在聚合中,依赖对象是独立的,即使拥有类的对象已死,它也可以存在。
  • 因此,在组合中,如果拥有的对象被垃圾收集,则拥有的对象也将被垃圾收集,而聚合中的情况并非如此。

使困惑?

组合示例:考虑汽车和非常特定于该汽车的引擎的示例(这意味着它不能用于任何其他汽车)。CarSpecificEngine类之间的这种关系称为组合。Car 类的对象没有SpecificEngine 类的对象就不能存在,SpecificEngine 的对象没有Car 类就没有意义。简单来说,Car 类完全“拥有”SpecificEngine 类。

聚合示例:现在考虑Car类和Wheel类。Car 需要一个 Wheel 对象才能运行。这意味着 Car 对象拥有 Wheel 对象,但我们不能说 Wheel 对象没有 Car 对象就没有意义。它可以很好地用于自行车、卡车或不同的汽车对象。

总结一下——

总而言之,关联是一个非常通用的术语,用于表示一个类何时使用另一个类提供的功能。如果一个父类对象拥有另一个子类对象,并且如果没有父类对象,该子类对象就不能有意义地存在,我们说它是组合。如果可以,则称为聚合。

更多细节在这里。 我是http://opensourceforgeeks.blogspot.in的作者,并在上面添加了指向相关帖子的链接以获取更多上下文。

于 2014-11-09T12:38:52.180 回答
126

关联是关系的广义概念。它包括组合和聚合。

组合混合)是一种将简单对象或数据类型包装成单个单元的方法。组合是许多基本数据结构的关键组成部分

聚合将许多事物组成一个集群)与普通组合的不同之处在于它并不意味着所有权。在组合中,当拥有对象被销毁时,包含的对象也会被销毁。在聚合中,这不一定是正确的。

记住区别的技巧

  • “有- A ”:一个聚集
  • “ Part- O f ”:c O m P ositoin
  • I s-a”:继承
语境 聚合 作品
寿命 对象有自己的生命周期,没有所有者 由拥有它的整体或父母控制
范围 父对象和子对象是独立的 父对象也意味着其子对象的死亡。
关系 有个 部分
力量 弱关系 强关系。
现实生活中的例子 汽车和司机 汽车和车轮

现在让我们观察下图

关系

在此处输入图像描述

比喻:

构图:下图是图像构图,即使用单个图像制作一张图像。
在此处输入图像描述

聚合:在单个位置收集图像

在此处输入图像描述

例如,一所大学拥有多个系,每个系都有多名教授。如果大学关闭,这些系将不复存在,但这些系的教授将继续存在。因此,大学可以看作是系的组合,而系则是教授的集合。此外,教授可以在多个系工作,但一个系不能隶属于多个大学。

于 2015-07-24T00:01:15.053 回答
101

依赖(引用)
这意味着两个对象之间没有概念上的联系。例如 EnrollmentService 对象引用 Student 和 Course 对象(作为方法参数或返回类型)

public class EnrollmentService {
    public void enroll(Student s, Course c){}
}

关联(has-a)
这意味着对象之间几乎总是存在链接(它们是关联的)。Order 对象有一个Customer 对象

public class Order {
    private Customer customer
}

聚合(has-a + whole-part)
特殊类型的关联,其中两个对象之间存在整体关系。不过,他们可能会在没有彼此的情况下生活。

public class PlayList {
    private List<Song> songs;
}

或者

public class Computer {
    private Monitor monitor;
}

注意:最棘手的部分是将聚合与正常关联区分开来。老实说,我认为这可以接受不同的解释。

组合(拥有+整体+所有权)
特殊类型的聚合。AnApartment由一些Rooms组成。没有ARoom就不能存在Apartment。当一个公寓被删除时,所有相关的房间也会被删除。

public class Apartment{
    private Room bedroom;
    public Apartment() {
       bedroom = new Room();
    }
}
于 2015-12-03T15:24:55.667 回答
31

来自Robert Martin 在 comp.object 中的帖子:

关联表示一个实例向另一个实例发送消息的能力。这通常使用指针或引用实例变量来实现,尽管它也可以作为方法参数或创建局部变量来实现。

//[Example:]

//|A|----------->|B|

class A
{
  private:
    B* itsB;
};

聚合 [...] 是典型的整体/部分关系。这与关联完全相同,只是实例不能具有循环聚合关系(即一部分不能包含其整体)。

//[Example:]

//|Node|<>-------->|Node|

class Node
{
  private:
    vector<Node*> itsNodes;
};

这是聚合的事实意味着 Node 的实例不能形成循环。因此,这是一个节点树而不是节点图。

组合 [...] 与聚合完全相同,只是“部分”的生命周期由“整体”控制。这种控制可以是直接的或传递的。也就是说,“整体”可能直接负责创建或破坏“部分”,或者它可能接受已经创建的部分,然后将其传递给其他承担责任的整体。

//[Example:]

//|Car|<#>-------->|Carburetor|

class Car
{
  public:
    virtual ~Car() {delete itsCarb;}
  private:
    Carburetor* itsCarb
};
于 2010-02-01T07:15:46.933 回答
27

正如其他人所说,关联是对象之间的关系,聚合和组合是关联的类型。

从实现的角度来看,聚合是通过引用类成员来获得的。例如,如果 A 类聚合了 B 类的一个对象,你会得到这样的东西(在 C++ 中):

class A {
    B & element;
  // or B * element;
};

聚合的语义是当一个对象 A 被销毁时,它所存储的 B 对象仍然存在。使用组合时,您有更强的关系,通常通过按值存储成员:

class A {
    B element;
};

在这里,当一个 A 对象被销毁时,它包含的 B 对象也将被销毁。实现这一点的最简单方法是按值存储成员,但您也可以使用一些智能指针,或在析构函数中删除成员:

class A {
    std::auto_ptr<B> element;
};

class A {
    B * element;

    ~A() {
        delete B;
    }
};

重要的一点是,在组合中,容器对象拥有包含的对象,而在聚合中,它引用它。

于 2009-05-20T08:16:08.820 回答
19

令人惊讶的是,对于关联聚合组合这三个关系概念之间的区别存在多少混淆。

请注意,术语聚合组合已经在 C++ 社区中使用,可能在它们被定义为UML 类图中的特殊关联案例之前已经有一段时间了。

主要问题是普遍和持续的误解(甚至在专业软件开发人员中),即组合的概念意味着整体与其部分之间存在生命周期依赖关系,因此如果没有整体,部分就无法存在,而忽略了以下事实:部分-整体-关联与不可共享部分的情况,其中部分可以与整体分离并在整体破坏中幸存下来。

据我所知,这种混乱有两个根源:

  1. 在 C++ 社区中,术语“聚合”用于定义用于引用另一个独立类的对象的属性的类的含义(例如,参见 [1]),这是UML 类图中的关联含义。术语“组合”用于为其对象定义组件对象的类,这样在组合对象被破坏时,这些组件对象也被破坏。

  2. 在 UML 类图中,“聚合”和“组合”都被定义为表示部分-整体关系的关联的特殊情况(在哲学中已经讨论了很长时间)。在他们的定义中,“聚合”和“组合”之间的区别是基于它是否允许在两个或多个整体之间共享一部分的事实。他们将“组合”定义为具有不可共享(独占)的部分,而“聚合”可以共享它们的部分。此外,他们说类似以下的话:很多时候,但并非在所有情况下,组合在整体与其部分之间存在生命周期依赖关系,因此如果没有整体,部分就无法存在。

因此,虽然 UML 将术语“聚合”和“组合”置于正确的上下文中(部分-整体关系),但它们并没有设法以清晰明确的方式定义它们,从而捕捉到开发人员的直觉。然而,这并不奇怪,因为这些关系可以有很多不同的属性(和实现的细微差别),并且开发人员在如何实现它们上没有达成一致。

另请参阅我对下面列出的 2009 年 4 月的 SO 问题的扩展答案。

并且假定定义 C++ 社区中 OOP 对象之间“组合”的属性(并且这种信念仍然被广泛持有):两个相关对象(组合及其组件)之间的运行时生命周期依赖关系是并不是“组合”的真正特征,因为在其他类型的关联中我们也可以由于参照完整性而具有这种依赖关系。

例如,在SO answer中提出了以下“组合”的代码模式:

final class Car {    
  private final Engine engine;

  Car(EngineSpecs specs) {
    engine = new Engine(specs);
  }

  void move() {
    engine.work();
  }
}

受访者声称,“组合”的特点是没有其他类可以引用/知道该组件。然而,对于所有可能的“组合”情况,这肯定不是真的。特别是,在汽车发动机的情况下,汽车制造商(可能在另一个类的帮助下实施)可能必须引用发动机,以便在出现问题时能够联系车主。

[1] http://www.learncpp.com/cpp-tutorial/103-aggregation/

附录 - StackOverflow 上关于组合与聚合的重复提问的不完整列表

[ 2009 年 4 月]
聚合与组合[主要基于意见关闭]
[ 2009 年 4 月]
组合和关联关系有什么区别?
[ 2009 年 5 月]
关联、聚合和组合
之间的区别 [ 2009 年 5 月]
组合和聚合之间有什么区别?[重复]
[ 2009 年 10 月]
聚合、组合和依赖有什么区别?[标记为重复]
[ 2010 年 11 月]
关联与聚合[标记为重复]
[2012 年 8 月]
Java 中聚合和组合之间的实现差异
[ 2015 年 2 月]
UML - 关联或聚合(简单代码片段)

于 2016-02-05T01:08:49.160 回答
14

Association

Association represents the relationship between two classes.It can be unidirectional(one way) or bidirectional(two way)

for example:

  1. unidirectional

Customer places orders

  1. bidirectional

A is married to B

B is married to A

Aggregation

Aggregation is a kind of association.But with specific features.Aggregation is the relationship in one larger "whole" class contains one or more smaller "parts" classes.Conversely, a smaller "part" class is a part of "whole" larger class.

for example:

club has members

A club("whole") is made up of several club members("parts").Member have life to outside the club. If the club("whole") were to die, members("parts") would not die with it. Because member can belong to multiple clubs("whole").

Composition

This is a stronger form of aggregation."Whole" is responsible for the creation or destruction of its "parts"

For example:

A school has departments

In this case school("whole") were to die, department("parts") would die with it. Because each part can belong to only one "whole".

于 2016-07-13T17:51:50.367 回答
10

重要的是要理解为什么我们甚至应该费心使用不止一次的关系线。最明显的原因是描述类之间的父子关系(当父删除时,它的所有子都被删除),但更无能为力的是,我们想区分简单关联和组合,以便对可见性和将更改传播到相关类,这在理解和降低系统复杂性方面起着重要作用。

协会

描述类之间静态关系的最抽象方式是使用关联链接,它简单地说明两个或多个类之间存在某种链接或依赖关系。

弱关联

ClassA 可以链接到 ClassB 以表明其方法之一包括 ClassB 实例的参数,或返回 ClassB 的实例。

强大的协会

ClassA 也可以链接到 ClassB 以表明它持有对 ClassB 实例的引用。

聚合(共享关联)

如果ClassA(整体)和ClassB(部分)之间存在部分关系,我们可以更具体地使用聚合链接而不是关联链接,强调ClassB也可以被应用程序中的其他类聚合(因此聚合也称为共享关联)。

在此处输入图像描述

重要的是要注意,聚合链接没有以任何方式声明 ClassA 拥有 ClassB ,也没有说明两者之间存在父子关系(当父删除时,其所有子都被删除)。其实,恰恰相反!聚合链接通常用来强调ClassA不是ClassB的专有容器,实际上ClassB还有另一个容器。

聚合与关联 关联链接可以在任何情况下替换聚合链接,而聚合不能在类之间只有“弱链接”的情况下替换关联,即 ClassA 具有包含 ClassB 参数但 ClassA 没有的方法/s持有对 ClassB 实例的引用。

Martin Fowler 建议根本不应该使用聚合链接,因为它没有附加价值并且会扰乱一致性,引用 Jim Rumbaugh 的话“将其视为建模安慰剂”。

组成(非共享关联)

我们应该更具体,并在除了 ClassA 和 ClassB 之间的部分关系之外的情况下使用组合链接 - 两者之间存在很强的生命周期依赖关系,这意味着当 ClassA 被删除时,ClassB 也因此被删除

在此处输入图像描述

组合链接显示一个类(容器,整体)对其他类(部分)具有独占所有权,这意味着容器对象及其部分构成父子关系。

与关联和聚合不同,在使用组合关系时,组合类不能作为组合类的返回类型或参数类型出现。因此,对组合类的更改不能传播到系统的其余部分。因此,组合的使用限制了复杂性随着系统的增长而增长。

测量系统复杂性

可以通过查看 UML 类图并评估关联、聚合和组合关系线来简单地测量系统复杂性。衡量复杂性的方法是确定更改特定类可以影响多少类。如果 A 类公开 B 类,那么理论上使用 A 类的任何给定类都可能受到 B 类更改的影响。系统中每个类的潜在受影响类的数量之和就是系统的总复杂度。

您可以在我的博客上阅读更多内容:http: //aviadezra.blogspot.com/2009/05/uml-association-aggregation-composition.html


于 2017-02-20T05:31:39.007 回答
7

组成(如果你删除“整体”,“部分”也会自动删除 - “所有权”)

  • 在新类中创建现有类的对象。这称为组合,因为新类由现有类的对象组成。

  • 通常使用普通的成员变量。

  • 如果组合类自动处理负责创建/销毁子类的分配/解除分配,则可以使用指针值。

在此处输入图像描述

C++ 中的组合

#include <iostream>
using namespace std;
/********************** Engine Class ******************/
class Engine
{
    int nEngineNumber;
    public:
    Engine(int nEngineNo);
    ~Engine(void);
};
Engine::Engine(int nEngineNo)
{
    cout<<" Engine :: Constructor " <<endl;
}
Engine::~Engine(void)
{
    cout<<" Engine :: Destructor " <<endl;
}
/********************** Car Class ******************/
class Car
{
    int nCarColorNumber;
    int nCarModelNumber;
    Engine objEngine;
    public:
    Car (int, int,int);
    ~Car(void);
};
Car::Car(int nModelNo,int nColorNo, int nEngineNo):
nCarModelNumber(nModelNo),nCarColorNumber(nColorNo),objEngine(nEngineNo)
{
    cout<<" Car :: Constructor " <<endl;
}
Car::~Car(void)
{
    cout<<" Car :: Destructor " <<endl;
    Car
    Engine
    Figure 1 : Composition
}
/********************** Bus Class ******************/
class Bus
{
    int nBusColorNumber;
    int nBusModelNumber;
    Engine* ptrEngine;
    public:
    Bus(int,int,int);
    ~Bus(void);
};
Bus::Bus(int nModelNo,int nColorNo, int nEngineNo):
nBusModelNumber(nModelNo),nBusColorNumber(nColorNo)
{
    ptrEngine = new Engine(nEngineNo);
    cout<<" Bus :: Constructor " <<endl;
}
Bus::~Bus(void)
{
    cout<<" Bus :: Destructor " <<endl;
    delete ptrEngine;
}
/********************** Main Function ******************/
int main()
{
    freopen ("InstallationDump.Log", "w", stdout);
    cout<<"--------------- Start Of Program --------------------"<<endl;
    // Composition using simple Engine in a car object
    {
        cout<<"------------- Inside Car Block ------------------"<<endl;
        Car objCar (1, 2,3);
    }
    cout<<"------------- Out of Car Block ------------------"<<endl;
    // Composition using pointer of Engine in a Bus object
    {
        cout<<"------------- Inside Bus Block ------------------"<<endl;
        Bus objBus(11, 22,33);
    }
    cout<<"------------- Out of Bus Block ------------------"<<endl;
    cout<<"--------------- End Of Program --------------------"<<endl;
    fclose (stdout);
}

输出

--------------- Start Of Program --------------------
------------- Inside Car Block ------------------
Engine :: Constructor
Car :: Constructor
Car :: Destructor
Engine :: Destructor
------------- Out of Car Block ------------------
------------- Inside Bus Block ------------------
Engine :: Constructor
Bus :: Constructor
Bus :: Destructor
Engine :: Destructor
------------- Out of Bus Block ------------------
--------------- End Of Program --------------------

聚合(如果删除“整体”,“部分”可以存在 - “无所有权”)

  • 聚合是一种特定类型的组合,其中不暗示复杂对象和子对象之间的所有权。当聚合被销毁时,子对象不会被销毁。

  • 通常使用指向位于聚合类范围之外的对象的指针变量/引用变量

  • 可以使用指向位于聚合类范围之外的对象的引用值

  • 不负责创建/销毁子类

在此处输入图像描述

C++ 中的聚合代码

#include <iostream>
#include <string>
using namespace std;
/********************** Teacher Class ******************/
class Teacher
{
    private:
    string m_strName;
    public:
    Teacher(string strName);
    ~Teacher(void);
    string GetName();
};
Teacher::Teacher(string strName) : m_strName(strName)
{
    cout<<" Teacher :: Constructor --- Teacher Name :: "<<m_strName<<endl;
}
Teacher::~Teacher(void)
{
    cout<<" Teacher :: Destructor --- Teacher Name :: "<<m_strName<<endl;
}
string Teacher::GetName()
{
    return m_strName;
}
/********************** Department Class ******************/
class Department
{
    private:
    Teacher *m_pcTeacher;
    Teacher& m_refTeacher;
    public:
    Department(Teacher *pcTeacher, Teacher& objTeacher);
    ~Department(void);
};
Department::Department(Teacher *pcTeacher, Teacher& objTeacher)
: m_pcTeacher(pcTeacher), m_refTeacher(objTeacher)
{
    cout<<" Department :: Constructor " <<endl;
}
Department::~Department(void)
{
    cout<<" Department :: Destructor " <<endl;
}
/********************** Main Function ******************/
int main()
{
    freopen ("InstallationDump.Log", "w", stdout);
    cout<<"--------------- Start Of Program --------------------"<<endl;
    {
        // Create a teacher outside the scope of the Department
        Teacher objTeacher("Reference Teacher");
        Teacher *pTeacher = new Teacher("Pointer Teacher"); // create a teacher
        {
            cout<<"------------- Inside Block ------------------"<<endl;
            // Create a department and use the constructor parameter to pass the teacher to it.
            Department cDept(pTeacher,objTeacher);
            Department
            Teacher
            Figure 2: Aggregation
        } // cDept goes out of scope here and is destroyed
        cout<<"------------- Out of Block ------------------"<<endl;
        // pTeacher still exists here because cDept did not destroy it
        delete pTeacher;
    }
    cout<<"--------------- End Of Program --------------------"<<endl;
    fclose (stdout);
}

输出

--------------- Start Of Program --------------------
Teacher :: Constructor --- Teacher Name :: Reference Teacher
Teacher :: Constructor --- Teacher Name :: Pointer Teacher
------------- Inside Block ------------------
Department :: Constructor
Department :: Destructor
------------- Out of Block ------------------
Teacher :: Destructor --- Teacher Name :: Pointer Teacher
Teacher :: Destructor --- Teacher Name :: Reference Teacher
--------------- End Of Program --------------------
于 2018-03-13T10:14:45.433 回答
6

这些答案的问题在于它们只是故事的一半:它们解释了聚合和组合是关联的形式,但他们没有说关联是否有可能不是这两者。

我根据对 SO 上的许多帖子和一些 UML 文档的一些简短阅读收集到,类关联有 4 种主要的具体形式:

  1. 组成:A 由 B 组成;没有 A 就没有 B,就像家里的房间一样
  2. 聚合:A has-a B;B可以没有A而存在,就像教室里的学生一样
  3. 依赖:A使用-a B;A 和 B 之间没有生命周期依赖,例如方法调用参数、返回值或方法调用期间创建的临时值
  4. 概括:A is-a B

当两个实体之间的关系不是其中之一时,它可以被称为一般意义上的“关联”,并进一步描述其他方式(注、刻板印象等)。

我的猜测是“通用关联”主要用于两种情况:

  • 当关系的细节仍在制定中时;图表中的这种关系应尽快转换为实际的/将要的(其他 4 个之一)。
  • 当关系与 UML 预先确定的这 4 个中的任何一个都不匹配时;“通用”关联仍然为您提供了一种表示“不是其他关系之一”的关系的方式,这样您就不会因为使用带有注释的不正确关系而陷入困境“这实际上不是聚合,只是 UML没有我们可以使用的任何其他符号”
于 2016-12-19T20:04:54.737 回答
5

我认为这个链接会做你的功课: http: //ootips.org/uml-hasa.html

为了理解这些术语,我记得我早期编程时的一个例子:

如果您有一个“棋盘”对象,其中包含“框”对象,则该对象是合成的,因为如果删除了“棋盘”,则框就没有理由再存在了。

如果您有一个具有“颜色”对象的“正方形”对象并且该正方形被删除,则“颜色”对象可能仍然存在,即聚合

它们都是联想,主要区别是概念上的

于 2009-05-20T03:07:18.523 回答
5

https://www.linkedin.com/pulse/types-relationships-object-oriented-programming-oop-sarah-el-dawody/

组合:是一种“部分”关系。

例如“发动机是汽车的一部分”,“心脏是身体的一部分”。

在此处输入图像描述

关联:是一种“has-a”类型的关系

例如,假设我们有两个类,那么如果这两个实体在某些工作中共享彼此的对象,并且同时它们可以在没有彼此依赖关系的情况下存在,或者两者都有自己的自己的一生。

在此处输入图像描述

上面的例子展示了一个关联关系,因为 Employee 和 Manager 类都使用了彼此的对象以及它们各自独立的生命周期。

聚合:基于“has-a”关系,它是一种特殊的关联形式

例如,“学生”和“地址”。每个学生都必须有一个地址,因此学生类和地址类之间的关系将是“Has-A”类型的关系,反之亦然。

在此处输入图像描述

于 2020-01-12T01:37:22.717 回答
5
    Simple rules:
    A "owns" B = Composition : B has no meaning or purpose in the system 
    without A
    A "uses" B = Aggregation : B exists independently (conceptually) from A
    A "belongs/Have" B= Association; And B exists just have a relation
    Example 1:

    A Company is an aggregation of Employees.
    A Company is a composition of Accounts. When a Company ceases to do 
    business its Accounts cease to exist but its People continue to exist. 
    Employees have association relationship with each other.

    Example 2: (very simplified)
    A Text Editor owns a Buffer (composition). A Text Editor uses a File 
    (aggregation). When the Text Editor is closed,
    the Buffer is destroyed but the File itself is not destroyed.
于 2019-03-12T10:19:27.677 回答
4

Association, Aggregation,Composition是关于关系的。

Aggregation并且CompositionAssociation 更准确地描述关系的子集

Aggregation-独立的关系。对象可以通过构造函数、方法、setter 传递和保存在类中...

Composition-依赖关系。对象由所有者对象创建

*Association 是 sybtyping 的替代方法

于 2021-01-30T11:10:33.510 回答
4

组合:一旦你破坏了一个对象(学校),另一个绑定到它的对象(教室)也会被破坏。两者都不能独立存在。

聚合:这与上面的 ( Composition) 关联完全相反,一旦你杀死一个对象 ( ),绑定到它Company的另一个对象 ( ) 就可以单独存在。Employees

协会
组合和聚合是关联的两种形式。

于 2017-10-15T12:40:20.963 回答
3

来自:Remo H. Jansen 的书《Beginning React:Learning TypeScript 2.x - Second Edition》:

我们将那些对象具有独立生命周期且没有对象所有权的关系称为关联。让我们看一个老师和学生的例子。多个学生可以关联一个老师,一个学生可以关联多个老师,但两者都有独立的生命周期(都可以独立创建和删除)。所以,当老师离开学校时,我们不需要删除任何学生,当学生离开学校时,我们也不需要删除任何老师。

我们把那些对象有独立生命周期但有所有权的关系称为聚合,子对象不能属于另一个父对象。让我们以手机和手机电池为例。单个电池可以属于一部手机,但如果手机停止工作,并且我们将其从数据库中删除,手机电池将不会被删除,因为它可能仍然可以使用。因此,在聚合中,虽然有所有权,但对象有其生命周期

我们用组合一词来指代对象没有独立生命周期的关系,如果父对象被删除,所有子对象也会被删除。让我们举一个问题和答案之间的关系的例子。单个问题可以有多个答案,答案不能属于多个问题。如果我们删除问题,答案将被自动删除。

于 2019-07-26T23:38:10.650 回答
3

在一个非常简单的句子中:
聚合和组合是关联的子集。

  • A 使用 B -> 这是一个聚合

  • A 需要 B -> 是组合。

在这里阅读更多。

于 2018-10-04T20:27:28.197 回答
2

关联是两个独立类之间的关系,关联可以是任何类型,例如一对一、一对可能等。它连接了两个完全独立的实体。

聚合是一种特殊形式的关联,它是类(或实体)之间的单向单向关系,例如 Wallet 和 Money 类。钱包有钱,但钱不一定要有钱包,所以它是一种单向关系。在这种关系中,如果另一个条目结束,两个条目都可以生存。在我们的示例中,如果 Wallet 类不存在,并不意味着 Money 类不存在。

组合是聚合的一种受限形式,其中两个实体(或者你可以说是类)高度依赖于彼此。例如人类和心脏。人需要心脏才能生存,心脏需要人体才能生存。换句话说,当类(实体)相互依赖并且它们的寿命相同(如果一个人死了,那么另一个人也死了),那么它就是一个组合。如果 Human 类不存在,Heart 类就没有意义。

于 2019-12-23T15:04:56.197 回答
2

我想说明这三个术语是如何在 Rails 中实现的。ActiveRecord 将两个模型之间的任何类型的关系称为association. 在阅读文档或文章时,人们不会经常找到与 ActiveRecord 相关的术语composition和。aggregation通过将关联类宏之一添加到类的主体来创建关联。其中一些宏是belongs_to,has_onehas_many

如果我们想设置compositionor aggregation,我们需要添加belongs_to到拥有的模型(也称为子模型)和has_onehas_many到拥有的模型(也称为父模型)。我们是否设置compositionaggregation取决于我们传递给belongs_to子模型中的调用的选项。在 Rails 5 之前,belongs_to没有任何选项的设置会创建一个aggregation,孩子可以在没有父母的情况下存在。如果我们想要一个composition,我们需要通过添加选项来显式声明它required: true

class Room < ActiveRecord::Base
  belongs_to :house, required: true
end

在 Rails 5 中,这发生了变化。现在,默认情况下,声明belongs_to关联会创建一个composition,如果没有父级,子级就不能存在。所以上面的例子可以重写为:

class Room < ApplicationRecord
  belongs_to :house
end

如果我们想让子对象在没有父对象的情况下存在,我们需要通过选项显式声明optional

class Product < ApplicationRecord
  belongs_to :category, optional: true
end
于 2017-09-12T11:17:19.813 回答