关联、聚合和组合之间的区别是什么? 请从实施的角度加以说明。


当前回答

摘自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
};

其他回答

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

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

协会(有) 这意味着对象之间几乎总是有一个链接(它们是相关联的)。 Order对象有一个Customer对象

public class Order {
    private Customer customer
}

聚合(has-a + whole-part) 两个对象之间存在整体-部分关系的一种特殊联想。但他们可能没有彼此。

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

OR

public class Computer {
    private Monitor monitor;
}

注意:最棘手的部分是区分聚合和普通关联。老实说,我认为这有不同的解释。

组成(has-a +整体部分+所有权) 一种特殊的聚合。公寓是由一些房间组成的。没有公寓,就没有房间。删除一个公寓时,所有关联的房间也会被删除。

public class Apartment{
    private Room bedroom;
    public Apartment() {
       bedroom = new Room();
    }
}

关联是两个独立的类之间的关系,关联可以是任何类型,比如one to one, one to may等等。它连接了两个完全独立的实体。

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

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

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

Composition:是一种“part-of”关系。

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

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

例如,假设我们有两个类,那么这两个类被称为“has-a”关系,如果这两个实体为了某些工作而共享彼此的对象,同时它们可以不依赖彼此而存在,或者它们都有自己的生命期。

上面的示例显示了一种关联关系,因为Employee类和Manager类都使用彼此的对象,并且都有各自独立的生命周期。

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

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

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

从实现的角度来看,聚合是通过引用类成员来获得的。例如,如果类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;
    }
};

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

摘自:Remo H. Jansen的《Beginning React: Learning TypeScript 2》。x -第二版”:

We call association those relationships whose objects have an independent life cycle where there is no ownership of the objects. Let's take a look at an example of a teacher and a student. Multiple students can be associated with a single teacher, and a single student can be associated with multiple teachers, but both have independent life cycles (both can create and delete independently). So, when a teacher leaves the school, we don't need to delete any students, and when a student leaves the school, we don't need to delete any teachers.

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

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