关联、聚合和组合之间的区别是什么? 请从实施的角度加以说明。
当前回答
联想是关系的广义概念。它包括组合和聚合。
组合(混合)是一种将简单对象或数据类型包装成单个单元的方法。组合是许多基本数据结构的关键构建块
聚合(将许多事物形成一个集群)不同于普通的组合,因为它不意味着所有权。在组合中,当拥有的对象被销毁时,包含的对象也被销毁。总的来说,这并不一定正确。
记住区别的技巧:
“有一个”:聚合 “局部”:comPOsitoin “是一个”:继承
context | Aggregation | Composition |
---|---|---|
Life time | objects have their own lifetime and there is no owner | controlled by whole or parent that owns it |
Scope | parent objects and child objects are independent | parent object also means the death of its children. |
Relationship | Has-a | Part-of |
Strength | weak relationship | strong relationship. |
Real-life example | Car and Driver | Car and wheels |
现在让我们观察下面的图像
类比:
合成:下图是图像合成,即使用单独的图像合成一张图像。
聚合:图像在单一位置的集合
例如,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;
}
};
重要的一点是,在组合中,容器对象拥有被包含的对象,而在聚合中,它引用它。
对于Foo和Bar这两个对象,可以定义关系
关联——我与一个对象有一种关系。Foo使用Bar
public class Foo {
private Bar bar;
};
注意:请参阅Fowler的定义-关键是Bar在语义上与Foo相关,而不仅仅是一个依赖项(如int或字符串)。
组合——我拥有一个对象,我对它的生命周期负责。当Foo死了,Bar也死了
public class Foo {
private Bar bar = new Bar();
}
聚合——我有一个从别人那里借来的对象。当Foo死了,Bar可以活下去。
public class Foo {
private Bar bar;
Foo(Bar bar) {
this.bar = bar;
}
}
摘自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
};
我想说明如何在Rails中实现这三个术语。ActiveRecord将两个模型之间的任何类型的关系称为关联。在阅读文档或文章时,人们不会经常发现术语组合和聚合与ActiveRecord相关。通过向类的主体中添加一个关联类宏来创建关联。其中一些宏是belongs_to, has_one, has_many等。
If we want to set up a composition or aggregation, we need to add belongs_to to the owned model (also called child) and has_one or has_many to the owning model (also called parent). Wether we set up composition or aggregation depends on the options we pass to the belongs_to call in the child model. Prior to Rails 5, setting up belongs_to without any options created an aggregation, the child could exist without a parent. If we wanted a composition, we needed to explicitly declare this by adding the option required: true:
class Room < ActiveRecord::Base
belongs_to :house, required: true
end
在Rails 5中,这一点被改变了。现在,声明belongs_to关联在默认情况下创建了一个组合,子元素不能没有父元素而存在。所以上面的例子可以重写为:
class Room < ApplicationRecord
belongs_to :house
end
如果我们想要允许子对象在没有父对象的情况下存在,我们需要通过选项optional显式地声明这一点
class Product < ApplicationRecord
belongs_to :category, optional: true
end
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”类型的关系,反之亦然。
推荐文章
- 是什么导致这个ActiveRecord::ReadOnlyRecord错误?
- 在Java中使用“final”修饰符
- Rails:dependent =>:destroy VS:dependent =>:delete_all
- 我怎么知道什么时候创建一个接口?
- 构造函数vs工厂方法
- 在PHP5中创建单例设计模式
- 什么是依赖倒置原则?为什么它很重要?
- 从Java项目生成UML类图
- 为什么在Python方法中需要显式地有“self”参数?
- js:将一个组件包装成另一个组件
- 如何在方法中访问“静态”类变量?
- 为什么c#不提供c++风格的'friend'关键字?
- String, StringBuffer和StringBuilder
- 显示所有Elasticsearch聚合结果/桶,而不仅仅是10个
- 存储库和服务层的区别?