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


389

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


2
对于初学者来说这可能有点不知所措,但是请仔细浏览UML 2上层结构规范:omg.org/docs/formal/09-02-02.pdf关联的 第7.3.3节
chickeninabiscuit,2009年

6
我还应该补充一点,在UML 2中没有诸如聚合或组合之类的元素(尽管它在UML 1.4中)。在UML 2中,聚合​​/组合被实现为Association元素,并且AggregationKind属性设置为Shared或Composite。
chickeninabiscuit

已经有很多关于SO的答案:stackoverflow.com/search?
q=aggregation+and+composition


6
我知道这个问题已经被回答了很多次,但是我觉得我在这件事上读过的最好的解释就是:holub.com/goodies/uml/#composition
WLin

Answers:


384

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

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

public class Foo { 
    void Baz(Bar bar) {
    } 
};

构图 -我拥有一个对象,并对其生命负责。当Foo模具,这样做Bar

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

汇总 -我有一个东西是我从别人那里借来的。当Foo死亡时,Bar可能活下去。

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

3
似乎是C#/ Java代码。如果是这样,则关联代码和聚合代码都相同。在这两种情况下,仅引用“ bar”,并且Bar对象可能存在。
2014年

@Jeff Foster:我有些怀疑。如果我在Baz(Bar bar){bar = new Bar();中实例化bar对象,在第一种情况下。它仍将是联想还是现在成为组成?
萨凯特2014年

21
@Ajay:聚合保留对象的引用,而关联则不是。因此实现的差异。
ABCD 2015年

17
关联比仅仅用作方法参数要强一些。我相信您的关联代码段与Dependency关系相对应。您可能需要查看Martin Fowler的相关文章
Ahmad Abdelghany

5
@AhmadAbdelghany是正确的。第一个示例是依赖关系。第三个用于关联和聚合。
安德烈·瓦伦蒂

122

我知道这个问题被标记为C#,但是概念是非常通用的问题,例如此处的重定向。因此,我将在这里提供我的观点(从Java的观点来看,我比较自在一些偏见)。

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

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

在此处输入图片说明

  • 一个类的聚集和合成对象中,“拥有”另一类的对象
  • 但是有细微的差别。在《合成》中,所属类的对象所拥有的类的对象不能自己生存(也称为“死亡关系”)。它始终将作为其拥有对象的一部分存在,在聚合中,从属对象是独立的,并且即使拥有类的对象已死也可以存在。
  • 因此,在组成中,如果拥有对象是垃圾回收,那么拥有对象也将是垃圾收集,聚合中不是这种情况。

困惑?

构成示例:考虑一个汽车和一个特定于该汽车的引擎的示例(这意味着它不能在任何其他汽车中使用)。CarSpecificEngine类之间的这种关系称为Composition。如果没有SpecificEngine类的对象,则Car类的对象将不存在,而如果没有Car类,SpecificEngine的对象将不具有意义。用简单的话来说,Car类仅“拥有” SpecificEngine类。

汇总示例:现在考虑Class CarWheel类。汽车需要Wheel对象才能起作用。意思是Car对象拥有Wheel对象,但是如果没有Car对象,我们不能说Wheel对象没有意义。它非常适合用于自行车,卡车或其他汽车物体。

总结一下-

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

此处有更多详细信息。 我是http://opensourceforgeeks.blogspot.in的作者,并在上面添加了到相关帖子的链接,以获取更多背景信息。


8
我要问的是为什么您要回答5年前已经回答过的问题,但后来我读了您的博客条目,它比这里的某些答案提供的信息更多。已投票!
Donbhupi 2015年

2
我同意@Donbhupi,您的答案比其他答案更有意义和更正确
zish

1
当C#和Java开发人员声称仅在使用这些语言的原始类型上存在合成时,他们才使用合成。如果您想真正地了解组成,则必须使用C ++,其中对象实际上可以成为其他对象的一部分。不仅仅是浮在堆内存中并保持指向彼此的指针并声称有组成。–
所有人,

@每个人我都得出与您相同的结论,但是我不太确定。例如,假设我有一个特定类在语义上拥有的类,但是拥有的对象在其所有者已被垃圾收集器删除后被垃圾收集,是否被认为是一个组合?
保罗安德烈·哈克

我们可以使用托管内存在ac#代码中进行合成吗?
PauloAndréHaacke

85

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

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

聚集集合)与普通组成不同,因为它并不暗示所有权。在合成中,当拥有对象被破坏时,所包含的对象也会被破坏。总体而言,这不一定是正确的。

两者都表示物体之间的关系,只是强度不同。

绝招要记住的区别:有一个 - 一个 ggregation和Ø WN - ç Ø mpositoin

在此处输入图片说明

现在让我们观察下图

关系

在此处输入图片说明

比喻:

构图:以下图片是图像构图,即使用单个图像制作一张图像。
在此处输入图片说明

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

在此处输入图片说明

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


14
在阅读了很多有关此主题的内容后,此答案是最直观易懂的答案。应该放在维基百科上。
Jankapunkt

1
铰接精美。
Sid

关于聚合,您说“子对象属于一个父对象”。这是不正确的。共享聚合是有效的UML,即一个孩子属于多个父级。您在有关部门系教授的集合的示例中承认了这一点,因为您说一位教授可以为多个部门工作。
www.admiraalit.nl

@ www.admiraalit.nl AFAIK共享聚合并不意味着“一个孩子属于多个父母”,而是相反,多个孩子属于同一个父母。这是一个非综合性的汇总,因为即使父母死亡,孩子也可能存活更长的时间。
阿德霍克斯(Aderchox)

65

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

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

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

public class Order {
    private Customer customer
}

聚合(具有+整个部分)
特殊的一种关联,其中两个对象之间存在整个部分的关系。他们也许会彼此生活。

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

注意:最棘手的部分是区分聚集与正常关联。老实说,我认为这有不同的解释。

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

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

1
是的,确定对象关系的唯一棘手的部分是区分关联和聚合。其他一切都清楚了。从我+1
Fouad Boukredine

28

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

1
这个定义有多少权限?UML标准作者支持吗?我有工具支持吗?
reinierpost 2012年

1
是罗伯特·C·马丁。这对我来说已经足够授权:-)
Heliac '18

21

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

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

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


8
这应该是唯一被接受的答案。除了原始类型外,C#和Java中不存在合成。但是您会看到那些语言的开发人员“解释”了合成。合成意味着一个对象存在于另一个对象之内。在Java和C#中,您甚至无法做到这一点,所有内容都在堆上,您只需持有指向它的指针,它实际上是聚合而不是组合。C ++提供组合物..
人人

14

令人惊讶的是,关于三个关系概念的关联聚合组成之间的区别存在多少困惑。

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

主要问题是,广泛且持续的误解(即使在专家软件开发人员中也是如此),即组合的概念隐含着整体及其各个部分之间的生命周期依赖性,因此,如果没有整体,这些部分就无法存在,而忽略了事实也存在具有不可共享部分的部分整体关联的情况,这些部分可以与整体分离,并在整体破坏中幸免。

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

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

  2. 在UML类图中,“聚合”和“组成”都已定义为表示部分整体关系的关联的特殊情况(在哲学上已经讨论了很长时间)。在它们的定义中,“集合”和“组合”之间的区别基于以下事实:它允许在两个或更多整体之间共享一部分。他们将“组合”定义为具有不可共享的(排他的)部分,而“集合”可以共享其部分。另外,他们说类似以下内容:很多时候,但并非在所有情况下,合成物在整体及其各个部分之间都具有生命周期依赖性,因此,没有整体就不能存在这些部分。

因此,尽管UML将“聚合”和“组成”一词放在了(整体-整体关系)的正确上下文中,但它们并没有以清晰明确的方式定义它们,从而抓住了开发人员的直觉。但是,这并不奇怪,因为这些关系可以具有许多不同的属性(和实现的细微差别),并且开发人员在如何实现它们方面未达成共识。

另请参阅以下针对2009年4月SO问题的扩展答案

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

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

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-关联或聚合(简单代码段)


支持不完整的重复提问列表。
雅科(Jacco)

13

协会

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

例如:

  1. 单向

客户下订单

  1. 双向的

A已嫁给B

B嫁给了A

聚合

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

例如:

俱乐部有成员

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

组成

这是更强大的聚合形式。“整个”负责其“部分”的创建或破坏

例如:

学校有部门

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


在聚集的情况下。我应该使用 class Club(){ _member = new Member } 或把它作为参考class Club(){ addMember(Member member) { this._member = member } }

12

重要的是要理解为什么我们甚至还要烦恼使用不止一次的关系线。最明显的原因是描述类之间的父子关系(当父项删除其所有子项时,其结果将被删除),但是更无能为力的是,我们希望区分简单关联和组成,以便对可见性和将更改传播到相关类,这对理解和减少重要作用系统复杂性中。

协会

描述类之间静态关系的最抽象方法是使用“关联”链接,该链接简单地指出两个或更多类之间存在某种链接或依赖性。

弱协会

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

强大的协会

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

汇总(共享协会)

如果在ClassA(整个)和ClassB(部分)之间存在部分关系,我们可以更具体一些,并使用聚合链接代替关联链接,着重指出ClassB也可以由应用程序中的其他类聚合(因此,聚合也称为共享关联)。

在此处输入图片说明

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

聚合与关联 在每种情况下,关联链接都可以替换聚合链接,而在类之间仅存在“弱链接”的情况下,聚合不能替代关联,即,ClassA的方法包含ClassB的参数,而ClassA没有持有对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



好答案。1)作文示例的问题:冷手(作文)人。如果我创建了动物和睡眠类,那么睡眠(集合)人;睡眠(集合)动物。这是对的吗?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} }

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

谁拒绝了这个答案。您能解释一下拒绝投票的原因吗?
莎拉布

真正使我感到困惑的是,在很多情况下,它不是所有者持有该东西,而是它拥有的东西“持有”了所有者。例如,汽车没有Engine *类型的指针,但是Engine类具有Car类型的成员来存储拥有它的汽车。我不太理解,在这种情况下尤其是类的uml关系。
dudu

6

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

我根据对SO上的许多文章和一些UML文档的简短阅读而得出,类关联有4种主要的具体形式:

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

当两个实体之间的关系不是其中之一时,就该术语的一般意义而言,可以仅称为“关联”,并进一步描述其他方式(注释,构造型等)。

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

  • 当仍在制定关系的细节时;图表中的这种关系应尽快转换为实际的/将要的状态(其他4个之一)。
  • 当某个关系与UML预先确定的4个关系中的任何一个都不匹配时;“通用”关联仍然为您提供了一种表示“不是其他任何一个”关系的方式,这样您就不会因为注释不正确而使用了不正确的关系,“这实际上不是聚合,只是UML没有其他可以使用的符号”

1
如果排除所有其他选项,您将如何实现通用关联?如果A不是由B组成(B的值在A中),A不是B的集合(B的引用不在A中),则B不会从A继承/实现,B也不用作返回值,参数或内部值A的函数用法,几乎没有任何关系。
Dean P

1
@DeanP暂时可以是通用的,以后将转换为4个之一(然后变为可实现);或者它可能是一种不适合4的关系,例如您想要一个表示“看起来像”的关联,而没有通用关联,则您将被迫使用4中的一种,从而误导读者,而如果您使用一般情况下,您可能会对其进行注释或添加注释以解释其含义,并且大多数人仅在不了解该符号的情况下才阅读注释;)
Oliver

5

我认为此链接将为您做功课:http : //ootips.org/uml-hasa.html

为了理解这些术语,我记得在编程的初期就有一个例子:

如果你有一个包含“盒子”对象“棋盘”对象,它是组成,因为如果“棋盘”被删除,没有理由对已经不复存在的框。

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

他们都是协会,主要区别是概念


5

组成:在这里,一旦销毁一个对象(学校),绑定到该对象的另一个对象(教室)也将被销毁。他们两个不能独立存在。

聚集:这与上述(Composition)关联完全相反,在该关联中,一旦杀死一个对象(Company),Employees绑定到该对象的另一个对象()就可以独立存在。

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


1
严格来说,公司的员工离不开公司。的确,您不会杀死人民,但他们不再是该公司的雇员。因此,我认为将分支机构和员工作为一个更好的类比,即使分支机构关闭,他们也可能继续是公司的员工。
亚历山大

1
是的,绝对。同意... +1感谢@AlexPopov指出来。:)
库拉桑加(Kulasangar)

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


2

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

如果要设置compositionor aggregation,则需要添加belongs_to到拥有的模型(也称为子级)和has_onehas_many到拥有的模型(也称为父级)中。我们是建立composition还是aggregation依赖于传递给belongs_to子模型中的调用的选项。在Rails 5之前,belongs_to不创建任何选项的设置会创建aggregation,子级可能没有父级就存在。如果需要a 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

2

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

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

我们称聚合那些对象具有独立生命周期但有所有权的关系,子对象不能属于另一个父对象。让我们以手机和手机电池为例。一块电池可以属于一部电话,但是如果该电话停止工作,并且我们从数据库中删除了该电池,则由于该电池仍可以工作,因此不会删除该电池。因此,总的来说,在拥有所有权的同时,对象具有其生命周期

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


1

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

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

组合是聚合的一种受限形式,其中两个实体(或您可以说是类)彼此高度依赖。例如人类和心脏。人需要心脏才能生存,而心脏则需要人体才能生存。换句话说,当类别(实体)彼此依赖并且它们的寿命相同时(如果一个人死亡,另一个人也死亡),则其组成。如果没有人类阶级,那么心脏阶级就没有意义。


1

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

组成:是“部分”关系。

例如“引擎是汽车的一部分”,“心脏是身体的一部分”。

在此处输入图片说明

关联:是一种“具有”关系

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

在此处输入图片说明

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

聚合:基于“具有”关系,是\\一种特殊的关联形式

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

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.