关联、聚合和组合之间的区别是什么? 请从实施的角度加以说明。
当前回答
依赖性(引用) 这意味着两个物体之间没有概念上的联系。例如: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();
}
}
其他回答
协会
关联表示两个类之间的关系。它可以是单向的(单向)或双向的(双向)
例如:
单向
客户下单
双向
A和B结婚了 B和A结婚了
聚合
聚合是一种关联。但是有特定的特征。聚合是一个较大的“整体”类包含一个或多个较小的“部分”类之间的关系。相反,一个较小的“部分”类是“整个”较大类的一部分。
例如:
俱乐部有会员
一个俱乐部(“整体”)是由几个俱乐部成员(“部分”)组成的。会员可以在俱乐部外生活。如果俱乐部(“整体”)死亡,成员(“部分”)不会随之死亡。因为会员可以属于多个俱乐部(“整体”)。
作文
这是一种更强的聚合形式。“整体”对其“部分”的创造或破坏负责
例如:
学校有院系
在这种情况下,学校(“整体”)将消亡,部门(“部分”)将随之消亡。 因为每个部分只能属于一个“整体”。
我想这个链接可以帮到你:http://ootips.org/uml-hasa.html
为了理解这些术语,我记得我早期编程时的一个例子:
如果你有一个" chess board "对象它包含" box "对象那就是组合因为如果" chess board "被删除了盒子就没有理由再存在了。
如果你有一个'square'对象,它有一个'color'对象,正方形被删除了,'color'对象可能仍然存在,这就是聚合
它们都是关联,主要的区别是概念上的
组合(如果你删除“整体”,“部分”也会自动删除-“所有权”)
在新类中创建现有类的对象。这称为组合,因为新类是由现有类的对象组成的。 通常使用普通成员变量。 如果组合类自动处理负责创建/销毁子类的分配/回收,则可以使用指针值。
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 --------------------
正如其他人所说,关联是对象之间的关系,聚合和组合是关联的类型。
从实现的角度来看,聚合是通过引用类成员来获得的。例如,如果类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++社区中使用,可能在它们被定义为UML类图中关联的特殊情况之前已经有一段时间了。
主要的问题是广泛的和持续的误解(甚至在专家软件开发人员中),组合的概念意味着整体和它的部分之间的生命周期依赖关系,以至于部分不能没有整体而存在,忽略了这样一个事实,即也存在与不可共享部分的部分-整体-关联的情况,其中部分可以从整体中分离出来,并且在整体被破坏后仍然存在。
在我看来,这种困惑有两个根源:
In the C++ community, the term "aggregation" was used in the sense of a class defining an attribute for referencing objects of another independent class (see, e.g., [1]), which is the sense of association in UML Class Diagrams. The term "composition" was used for classes that define component objects for their objects, such that on destruction of the composite object, these component objects are being destroyed as well. In UML Class Diagrams, both "aggregation" and "composition" have been defined as special cases of associations representing part-whole relationships (which have been discussed in philosophy for a long time). In their definitions, the distinction between an "aggregation" and a "composition" is based on the fact if it allows sharing a part between two or more wholes. They define "compositions" as having non-shareable (exclusive) parts, while "aggregations" may share their parts. In addition they say something like the following: very often, but not in all cases, compositions come with a life-cycle dependency between the whole and its parts such that the parts cannot exist without the whole.
因此,尽管UML将术语“聚合”和“组合”放在了正确的上下文中(部分-整体关系),但是他们并没有设法以一种清晰和明确的方式来定义它们,从而捕捉开发人员的直觉。然而,这并不奇怪,因为这些关系可以有很多不同的属性(和实现的细微差别),开发人员对如何实现它们没有一致的意见。
请参见我对2009年4月SO问题的扩展回答。
c++社区中定义OOP对象之间“组合”的属性(这个信念仍然被广泛持有):两个相关对象(组合及其组件)之间的运行时生命周期依赖关系并不是“组合”的真正特征,因为在其他类型的关联中,我们也可以由于引用完整性而具有这种依赖关系。
例如,在一个SO回答中提出了以下“composition”的代码模式:
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上的组合与聚合的反复询问问题的不完整列表
[Apr 2009] Aggregation versus Composition [closed as primarily opinion-based by] [Apr 2009] What is the difference between Composition and Association relationship? [May 2009] Difference between association, aggregation and composition [May 2009] What is the difference between composition and aggregation? [duplicate] [Oct 2009] What is the difference between aggregation, composition and dependency? [marked as duplicate] [Nov 2010] Association vs. Aggregation [marked as duplicate] [Aug 2012] Implementation difference between Aggregation and Composition in Java [Feb 2015] UML - association or aggregation (simple code snippets)