我很难理解UML中的组合和聚合之间的区别。有人可以给我一个很好的比较和对比吗?我也很想学习识别代码之间的区别和/或看一个简短的软件/代码示例。
编辑:我问的部分原因是因为我们在工作中正在进行反向文档活动。我们已经编写了代码,但是我们需要返回并为代码创建类图。我们只想正确捕获关联。
我很难理解UML中的组合和聚合之间的区别。有人可以给我一个很好的比较和对比吗?我也很想学习识别代码之间的区别和/或看一个简短的软件/代码示例。
编辑:我问的部分原因是因为我们在工作中正在进行反向文档活动。我们已经编写了代码,但是我们需要返回并为代码创建类图。我们只想正确捕获关联。
Answers:
聚集与构成之间的区别取决于上下文。
以另一个答案中提到的汽车示例为例-是的,的确,汽车排气装置可以“独立”站立,因此可能与汽车的组成不同-但这取决于应用程序。如果您构建的应用程序实际上必须处理独立的汽车尾气(汽车商店管理应用程序?),那么聚合将是您的选择。但是,如果这是一个简单的赛车游戏,并且汽车尾气仅充当汽车的一部分-那么,构图会很好。
棋盘?同样的问题。没有棋盘,只有在某些应用程序中,棋子才不存在。在其他玩具制造商中,象棋棋子肯定不能组成棋盘。
尝试将合成/聚合映射到您喜欢的编程语言时,情况变得更糟。在某些语言中,区别可能更容易注意到(在简单的情况下,“按引用”与“按值”对比),但在另一些语言中可能根本不存在。
还有最后的建议吗?不要在这个问题上浪费太多时间。这是不值得的。这种区别在实践中几乎没有用(即使您具有完全清晰的“组成”,由于技术原因(例如缓存),您可能仍希望将其实现为聚合)。
根据经验:
class Person {
private Heart heart;
private List<Hand> hands;
}
class City {
private List<Tree> trees;
private List<Car> cars
}
在组成上(人物,心,手)中,“人物”被破坏后,“子对象”(心,手)将被破坏。
合计(城市,树,汽车)中,当破坏城市时,“子对象”(树,汽车)不会被破坏。
最重要的是,组成强调相互存在,总的来说,不需要此属性。
组合和聚合是关联的类型。它们之间有着密切的联系,就编程而言,两者似乎没有太大的区别。我将尝试通过Java代码示例来解释这两者之间的区别
聚合:该对象存在于另一个对象之外,在外部创建,因此将其作为参数(例如)传递给构造函数。例如:人-汽车。汽车是在不同的上下文中创建的,然后成为个人财产。
// code example for Aggregation:
// reference existing HttpListener and RequestProcessor
public class WebServer {
private HttpListener listener;
private RequestProcessor processor;
public WebServer(HttpListener listener, RequestProcessor processor) {
this.listener = listener;
this.processor = processor;
}
}
组成:对象仅作为另一个的一部分存在,或仅在另一个内部有意义。例如:人–心。您不会创造一颗心,然后将其传递给一个人。相反,当创造人类时就创造了心脏。
// code example for composition:
// create own HttpListener and RequestProcessor
public class WebServer {
private HttpListener listener;
private RequestProcessor processor;
public WebServer() {
this.listener = new HttpListener(80);
this.processor = new RequestProcessor(“/www/root”);
}
}
这里以示例的方式进行说明,汇总和组成之间的区别
我学到的例子是手指到手。您的手由手指组成。它拥有它们。如果手死了,手指就死了。您不能“聚集”手指。您不能随便拿多余的手指,然后随意将它们从手上取下。
从设计的角度来看,这里的价值通常与对象寿命有关,正如另一位海报家所说。假设您有一个客户,并且他们有一个帐户。该帐户是客户的“组成”对象(至少在我能想到的大多数情况下)。如果删除客户,则该帐户本身没有价值,因此也将被删除。相反,在对象创建上通常是这样。由于帐户仅在客户的上下文中具有含义,因此您会在创建客户的过程中创建帐户(或者,如果懒惰地将其创建,则将成为某些客户交易的一部分)。
在设计中考虑哪些对象拥有(组成)其他对象与仅引用(汇总)其他对象的对象很有用。它可以帮助确定对象创建/清理/更新的责任。
就代码而言,通常很难说出来。代码中的大多数内容都是对象引用,因此所引用的对象是组成(拥有)还是聚合的可能并不明显。
令人惊讶的是许多混乱存在对之间的区别部分与整体 - 关联的概念聚集和组成。主要问题是普遍的误解(甚至在专家软件开发人员和UML的作者之间),即组合的概念隐含着整体及其各个部分之间的生命周期依赖性,因此,如果没有整体就不可能存在这些部分。但是,这种观点忽略了以下事实:在某些情况下,还存在与不可共享的零件存在部分整体关联的情况,这些零件可以与整体分离,并在整体破坏中幸存下来。
在UML规范文档中,术语“组合物”的定义始终暗含不可共享的部分,但是尚不清楚“组合物”的定义特征是什么,什么仅仅是可选特征。即使在新版本(截至2015年)中,UML 2.5在尝试改进术语“组合”的定义后,仍然仍然模棱两可,并且未提供任何指导如何使用非组合模型建模部分整体关联可共享的部分,可将这些部分从整体上拆下并在整体破坏中幸存下来,而不是无法将部分拆下并与整体一起破坏的情况。他们说
如果删除复合对象,则随即删除作为对象的所有零件实例。
但同时他们也说
在删除复合对象之前,可以从复合对象中删除零件对象,因此不能将其作为复合对象的一部分删除。
这种混乱指向UML定义的不完整,它不考虑组件和组合之间的生命周期依赖性。因此,重要的是要了解如何通过为<< 不可分割的 >>组合引入UML构造型来增强UML定义,在这种组合中,组件无法从其组合中分离出来,因此,只要销毁其组合,就必须将其销毁。
正如马丁·福勒(Martin Fowler)解释的那样,表征构图的主要问题是“一个对象只能是一个构图关系的一部分”。Geert Bellekens 在出色的博客文章UML Composition vs Aggregation vs Association中也对此进行了解释。除了组合物(具有排他的或不可共享的零件)的定义特征之外,组合物还可能在复合物及其组件之间具有生命周期依赖性。实际上,有两种此类依赖项:
Person
和之间的组成,以举例说明Heart
。当心脏所有者死亡时,心脏会被破坏或移植到另一个人。Person
和Brain
。总而言之,生命周期依赖性仅适用于特定的合成情况,但一般而言并不适用,因此它们不是定义特征。
UML规范指出:“部件可以在删除复合实例之前从复合实例中删除,因此不能作为复合实例的一部分被删除。” 在Car
- Engine
组成示例中,如下图所示,很明显的情况是,在损坏汽车之前可以将发动机从汽车上拆下,在这种情况下,发动机不会被损坏并且可以重新使用。这是由构图线的合成侧的零或一多重性暗示的。
合成组合端的合成关联末端的多样性为1或0..1,这取决于组件是否具有强制合成(必须连接到合成)的事实。如果组件是不可分割的,则意味着它们具有强制组合。
集合是具有部分整体关系的预期含义的另一种特殊关联形式,其中整体的各个部分可以与其他整体共享。例如,我们可以对类DegreeProgram
和之间的聚合进行建模Course
,如下图所示,因为课程是学位课程的一部分,并且课程可以在两个或多个学位课程之间共享(例如,工程学位可以共享C具有计算机科学学位的编程课程)。
但是,具有可共享部分的聚合的概念实际上并没有多大意义,因此它对实现没有任何影响,因此许多开发人员宁愿不在类图中使用白色菱形,而只是对简单关联建模代替。UML规范说:“共享聚合的精确语义因应用程序区域和建模者而异”。
聚合在整个端的关联端的多重性可以是任意数量(*),因为一部分可以属于任意数量的整体或在任意数量的整体之间共享。
用代码术语来说,组合通常建议包含对象负责创建component *的实例,而包含对象仅包含对其的长期引用。因此,如果父对象被取消引用并被垃圾回收,子对象也将被取消引用。
所以这段代码...
Class Order
private Collection<LineItem> items;
...
void addOrderLine(Item sku, int quantity){
items.add(new LineItem(sku, quantity));
}
}
建议LineItem是Order的组成部分-LineItem在其包含的订单之外不存在。但是Item对象不是按顺序构造的-即使商店没有订单,它们也会根据需要传递并继续存在。因此它们是关联的,而不是组件。
*容器负责实例化该组件,但实际上可能未调用new ...()本身-这是java,通常首先要经过一两个工厂!
我喜欢的示例: 成分: 水是池塘的一部分。(池塘是水的成分。) 聚集: 池塘里有鸭子和鱼(池塘里有鸭子和鱼)
如您所见,我将“ part-of”和“ has”加粗了,因为这两个短语通常可以指出类之间存在什么样的联系。
但是,正如其他人指出的那样,连接是组合还是聚集在很多情况下取决于应用程序。
考虑人体部分,例如肾脏,肝脏,大脑。如果我们尝试在此处映射组成和聚合的概念,则将类似于:
在诸如肾脏和肝脏的身体部位移植出现之前,这两个身体部位与人体组成,不能与人体隔离。
但是随着人体器官移植的出现,它们可以被移植到另一个人体中,因此这些部位与人体聚集在一起,因为它们现在可能与人体隔离存在。