ChatGPT解决这个技术问题 Extra ChatGPT

关联,聚合和组合之间有什么区别?

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

我还应该补充一点,在 UML 2 中没有聚合或组合这样的元素(虽然它在 UML 1.4 中)。在 UML 2 中,聚合/组合被实现为关联元素,其中 AggregationKind 属性设置为 Shared 或 Composite。
已经有很多关于 SO 的答案:stackoverflow.com/search?q=aggregation+and+composition
有用的文章在这里codeproject.com/Articles/22769/…
我知道这已经被回答了很多次,但我觉得我读过的关于这个问题的最好解释是这个:holub.com/goodies/uml/#composition
当我们在对象之间有任何关系时,称为关联。聚合和组合都是关联的特殊形式。组合再次是聚合的特殊形式。 javabench.in/2011/08/difference-between-association.html

J
Jeff Foster

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

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

public class Foo {         
    private Bar bar;
};

注意:参见 Fowler's definition - 关键是 Bar 在语义上与 Foo 相关,而不仅仅是依赖关系(如 intstring)。

作文 - 我拥有一个对象,我对它的生命周期负责。 Foo 死了,Bar 也死了

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

聚合 - 我有一个从别人那里借来的对象。 Foo 死后,Bar 可能会继续存在。

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

似乎是 C#/Java 代码。如果是这种情况,则关联和聚合代码都是相同的。在这两种情况下,“bar”只是被引用并且 Bar 对象可能存在。
@Ajay:聚合保留对象的引用,而关联不是这种情况。因此实现的差异。
Association 比仅用作方法参数要强一些。我相信您的关联代码片段更多地对应于 Dependency 关系。您可能需要检查 Martin Fowler related article
@AhmadAbdelghany 是正确的。第一个例子是依赖关系。第三个用于关联和聚合。
抱歉,关联的示例不是关联,而是简单的使用依赖。关联意味着存在语义关系,即关联具体实例的链接。
i
ivomalinowskip

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

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

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

https://i.stack.imgur.com/jNyV5.jpg

在一个类的聚合和组合对象中“拥有”另一个类的对象。

但是有一个细微的差别。在组合中,由其所属类的对象所拥有的类的对象不能靠它自己生存(也称为“死亡关系”)。它将始终作为其拥有对象的一部分存在,而在聚合中,依赖对象是独立的,即使拥有类的对象已死,它也可以存在。

因此,在组合中,如果拥有的对象被垃圾收集,则拥有的对象也将被垃圾收集,而聚合中的情况并非如此。

使困惑?

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

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

总结一下——

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

More details here. 我是 http://opensourceforgeeks.blogspot.in 的作者,并在上方添加了指向相关帖子的链接以获取更多上下文。


我本来想问你为什么要回答一个 5 年前提出的已经回答的问题,但后来我读了你的博客文章,它比这里的一些答案提供的信息要多得多。点赞!
我同意@Donbhupi,您的回答比其他许多人都提供更多信息和正确
当 C# 和 Java 开发人员声称他们使用组合时,它只存在于这些语言的原始类型上,这真的很有趣。如果你想真正理解组合,你必须使用 C++,其中对象可以真正成为其他对象的一部分。不仅仅是在堆内存中浮动并持有彼此的指针并声称存在组合。
@Everyone 我得出了和你一样的结论,但我不太确定。例如,假设我有一个类在语义上由一个特定类拥有,但是拥有的对象在其所有者已被垃圾收集器删除后被垃圾收集,它是否被视为组合?
@Everyone,当然,设计模式的实现可能会有所不同,具体取决于语言,但它们作为“设计模式”的实用性必然源于与实现基本无关。根据定义,组合总是意味着通过容器或通过容器进行生命周期管理。您描述的 C#/Java 场景可能只是聚合,其他人拥有“组合”对象,或者它是由于破坏封装而导致的错误实现,这在 C++ 中是尽可能的(暴露指向拥有的对象的指针, 例如)。
P
Premraj

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

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

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

记住区别的技巧:

“有-A”:聚合

“部分”:comPositoin

“Is-a”:继承

context 聚合组合 Life time 对象有自己的生命周期,没有由拥有它的整体或父对象控制的所有者 Scope 父对象和子对象是独立的父对象也意味着其子对象的死亡。关系有-一部分强度弱关系强关系。现实生活中的例子 Car and Driver 汽车和车轮

现在让我们观察下图

https://i.stack.imgur.com/jNyV5.jpg

https://i.stack.imgur.com/smuC7.jpg

比喻:

https://i.stack.imgur.com/WpA2O.jpg

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

https://i.stack.imgur.com/Al7u7.jpg

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


在阅读了这么多关于这个主题的内容之后,这个答案是最直观易懂的。应该放在维基百科上。
精美的表达。
关于聚合,您说“子对象属于单个父对象”。这是不正确的。共享聚合是有效的UML,即一个孩子属于多个父母。您在关于系的示例中承认这一点是教授的集合,因为您说教授可以为多个系工作。
@www.admiraalit.nl AFAIK 共享聚合并不意味着“一个孩子属于多个父母”,它只是反过来,多个孩子属于同一个父母。而且这是一个非复合聚合,因为即使父母死了,孩子也可能活得更久。
@aderchox 不,共享聚合意味着孩子(部分)由多个父母(整体)共享,所以 www.admiraalit.nl 是正确的:这个答案是不正确的。
A
Ahmad Abdelghany

依赖(引用) 这意味着两个对象之间没有概念上的联系。例如 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;
}

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

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

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

是的,确定对象关系的唯一棘手部分是区分关联和聚合。其他一切都很清楚。 +1 来自我
聚合和关联在实现 POV 中是否必须相同,因为唯一的区别是逻辑上的?我认为聚合和关联可以有类似集合的容器作为参考,因为这通常是由多重性决定的,与关系类型并不真正相关。
@AhmedAlhallag 是的,它们都以相同的方式实现,即“has-a”。我从来没有说聚合总是使用集合。我将尝试提出另一个不使用集合的示例以避免混淆。谢谢。
@AhmadAbdelghany 感谢您的澄清和您的努力。
d
decyclone

来自 Robert Martin in 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
};

这个定义有多少权威? UML 标准作者是否支持它?工具支持吗?
是罗伯特·C·马丁。这对我来说足够权威了:-)
L
Luc Touraille

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

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

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


这应该是唯一被接受的答案。除了原始类型之外,C# 和 Java 中不存在组合......但是你会看到这些语言的开发人员“解释”组合。组合意味着一个对象存在于另一个对象内部。在 Java 和 C# 中你甚至不能这样做,一切都在堆上,你只需持有指向它的指针,它实际上是聚合而不是组合。 C++ 提供组合..
经过一段时间的环顾,我认为这是对这个问题的最准确的答案
G
Gerd Wagner

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

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

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

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

在 C++ 社区中,术语“聚合”用于定义用于引用另一个独立类的对象的属性的类的含义(参见例如 [1]),这是 UML 类图中的关联含义。术语“组合”用于为其对象定义组件对象的类,这样在组合对象被破坏时,这些组件对象也被破坏。在 UML 类图中,“聚合”和“组合”都被定义为表示部分-整体关系的关联的特殊情况(在哲学中已经讨论了很长时间)。在他们的定义中,“聚合”和“组合”之间的区别是基于它是否允许在两个或多个整体之间共享一部分的事实。他们将“组合”定义为具有不可共享(独占)的部分,而“聚合”可以共享它们的部分。此外,他们还说了类似以下的话:很多时候,但并非在所有情况下,组合在整体与其部分之间存在生命周期依赖关系,因此如果没有整体,部分就无法存在。

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

另请参阅下面列出的 2009 年 4 月 SO 问题的 my extended answer

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

例如,在 an 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 月]
Aggregation versus Composition [主要基于意见关闭]
[2009 年 4 月]
What is the difference between Composition and Association relationship?
[ 2009 年 5 月]
Difference between association, aggregation and composition
[2009 年 5 月]
What is the difference between composition and aggregation? [重复]
[2009 年 10 月 strong>]
What is the difference between aggregation, composition and dependency? [标记为重复]
[2010 年 11 月]
Association vs. Aggregation [标记为重复]
[2012 年 8 月强>]
Implementation difference between Aggregation and Composition in Java
[2015 年 2 月]
UML - association or aggregation (simple code snippets)


为重复提出的问题的不完整列表投票。
C
Community

协会

关联表示两个类之间的关系,可以是单向(单向)或双向(双向)

例如:

单向

客户下订单

双向

嫁给 BB 嫁给 A

聚合

聚合是一种关联。但具有特定的特征。聚合是一个较大的“整体”类中包含一个或多个较小的“部分”类的关系。相反,较小的“部分”类是“整体”较大类的一部分.

例如:

俱乐部有会员

一个俱乐部(“整体”)由几个俱乐部成员(“部分”)组成。成员在俱乐部之外有生活。如果俱乐部(“整体”)死亡,成员(“部分”)不会随之死亡。因为会员可以属于多个俱乐部(“整体”)。

作品

这是一种更强的聚合形式。“整体”负责创建或销毁其“部分”

例如:

学校有部门

在这种情况下,学校(“整体”)将死亡,部门(“部分”)将随之死亡。因为每个部分只能属于一个“整体”。


在聚合的情况下。我应该使用 class Club(){ _member = new Member } 还是将其作为参考传递 class Club(){ addMember(Member member) { this._member = member } }
有趣的。但是我对您关于单向与双向的概念感到困惑。例如,在处理订单时,需要与客户关联才能找到要打印在标签上的名称,反之,在处理客户时,需要了解订单。这不是在两个方向上使用的同一个关系吗?
B
Bhargav Rao

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

协会

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

弱关联

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

强大的协会

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

聚合(共享关联)

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

https://i.stack.imgur.com/fLM7j.png

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

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

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

组成(非共享关联)

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

https://i.stack.imgur.com/EHOF0.png

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

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

测量系统复杂性

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

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


好答案。 1) 作文示例的问题:Leng 和 Hand(作文)人。如果我创建一个类 Animal 和 Sleep 然后 Sleep (agregation) Person;睡眠(聚合)动物。这是对的吗? 2)。手组成人:class Person() { private hand = new Hand }。睡眠聚合人 class Person() { private sleep = new Sleep } 在睡眠中使用“新”键是否有效?或者我应该将它作为参考传递,因为它是聚合? class Person() { private Sleep _sleep; public addSleep(Sleep sleep) { this._sleep = sleep} }
有趣的。但是你所说的弱关联在 UML 中不是称为关联,而是“使用依赖”。
S
Saurabh Raoot

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

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

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

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

https://i.stack.imgur.com/PL5KA.jpg

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

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

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

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

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

不负责创建/销毁子类

https://i.stack.imgur.com/alFxo.jpg

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

谁对这个答案投了反对票。你能解释一下拒绝投票的原因吗?
真正让我困惑的是,在很多情况下,并不是所有者持有这个东西,而是它所拥有的东西“持有”了所有者。例如,汽车没有 Engine * 类型指针,但 Engine 类有一个 Car 类型成员来存储拥有它的汽车。我不太明白,尤其是这种情况下类的 uml 关系。
O
Oliver

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

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

组成:A 由 B 组成;没有 A,B 就不存在,就像家庭聚合中的一个房间:A 有一个 B; B 可以在没有 A 的情况下存在,就像课堂依赖中的学生一样:A 使用-a B; A 和 B 之间没有生命周期依赖,例如方法调用参数、返回值或方法调用泛化期间创建的临时值:A is-a B

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

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

当关系的细节仍在制定中时;图表中的这种关系应尽快转换为实际的/将要的(其他 4 个之一)。

当关系与 UML 预先确定的这 4 个中的任何一个都不匹配时; “通用”关联仍然为您提供了一种表示“不是其他关系之一”的关系的方式,这样您就不会因为使用带有注释的不正确关系而陷入困境“这实际上不是聚合,只是 UML没有我们可以使用的任何其他符号”


如果排除所有其他选项,您将如何实现通用关联?如果 A 不是由 B 组成(B 的值在 A 中),A 不是 B 的聚合(B 的引用不在 A 中),B 不是从 A 继承/实现的,B 也不是用作返回、参数或内部A的函数用法,你几乎没有任何关系。
@DeanP 暂时可以只是通用的,以后会转换成4个之一(然后就变成可实现的了);或者它可能是不适合 4 的关系,比如说你想要一个意味着“看起来像”的关联,如果没有通用关联,你将被迫使用 4 中的一个,从而误导读者,而如果你使用通用的,您可能会对其进行注释或注释说明它是什么,并且大多数人仅在不理解该符号时才阅读注释;)
v
victor hugo

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

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

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

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

两者都是联想,主要区别是概念上的


N
Nouman Saleem
    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.

T
TheGeeky

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

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

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

https://i.stack.imgur.com/If6oW.jpg

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

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

https://i.stack.imgur.com/1ufIU.jpg

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

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

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

https://i.stack.imgur.com/bfsqy.jpg


关联可以是 UML 图中的一种方式,所以我无法理解您的关联和聚合示例之间的区别,它们看起来都是关联。地址不是学生的一部分,我认为聚合也定义了整体关系,至少根据 Bennetts 的书。
K
Kulasangar

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

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

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


严格来说,没有公司,公司的员工就不可能存在。确实,你不会杀了人,但他们不再是那家公司的员工。所以我认为一个更好的类比是分支机构和员工,即使分支机构关闭,他们也可能继续是公司的员工。
是的,绝对的。同意... +1 感谢@AlexPopov 指出这一点。 :)
H
H S Progr

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

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

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

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


y
yoAlex5

AssociationAggregationComposition 是关于关系的。

AggregationCompositionAssociation 的子集,更准确地描述了关系

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

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

*Association 是 sybtyping 的替代方法


P
Pang

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

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

需要 B -> 是组合。

阅读更多here


A
Alexander Popov

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

如果我们要设置 compositionaggregation,我们需要将 belongs_to 添加到拥有的模型(也称为子模型),并将 has_onehas_many 添加到拥有的模型(也称为父模型)。我们设置 composition 还是 aggregation 取决于我们传递给子模型中 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

M
Matloob Hasnain

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

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

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