聚合与组合

Dav*_*ave 86 java oop uml

我很难理解UML中组合和聚合之间的区别.有人可以给我一个很好的比较和对比吗?我也很想学会在代码中识别它们之间的区别和/或看一个简短的软件/代码示例.

编辑:我问的部分原因是因为我们正在进行的反向文档活动.我们编写了代码,但是我们需要返回并为代码创建类图.我们只是想正确地捕捉这些关联.

nxh*_*oaf 91

根据经验: 在此输入图像描述

class Person {
    private Heart heart;
    private List<Hand> hands;
}

class City {
    private List<Tree> trees;
    private List<Car> cars
}
Run Code Online (Sandbox Code Playgroud)

在构图(人物,心脏,手)中,一旦人物被摧毁,"子物体"(心脏,手)将被销毁.

在聚合(城市,树,汽车)中,当城市被摧毁时,"子对象"(树,汽车)将不会被销毁.

底线是,组合强调相互存在,而在聚合中,这个属性不是必需的.

  • 相互存在,好一个B-) (2认同)

Hex*_*gon 88

聚合和组合之间的区别取决于上下文.

以另一个答案中提到的汽车为例 - 是的,确实汽车尾气可以"独立",因此可能不会与汽车组成 - 但这取决于应用.如果您构建的应用程序实际上必须处理独立的汽车尾气(汽车商店管理应用程序?),那么聚合将是您的选择.但如果这是一个简单的赛车游戏,汽车尾气只能作为汽车的一部分 - 好吧,组成会很好.

国际象棋棋盘?同样的问题.只有在某些应用程序中,没有棋盘就不存在国际象棋棋子.在其他人(如玩具制造商的那些)中,棋子肯定不能组成棋盘.

在尝试将合成/聚合映射到您喜欢的编程语言时,情况变得更糟.在某些语言中,差异可能更容易被注意到("通过引用"与"按价值",当事情很简单时),但在其他语言中可能根本不存在.

还有最后一条忠告?不要在这个问题上浪费太多时间.这不值得.这种区别在实践中几乎没有用(即使你有一个完全清晰的"组合",你可能仍然希望将其作为聚合实现,因为技术原因 - 例如,缓存).

  • +1"不要浪费太多时间".这就是我需要听到的! (13认同)
  • 是的,你不应该在这个问题上浪费太多时间:UML是一种OOA/OOD语言; 聚合/组合通常是一个最好推迟到OOP的决策.如果你试图在你的UML模型中加入太多细节,你就会面临分析瘫痪的风险. (9认同)
  • "不要在此浪费太多时间"为什么采访者不理解这一点? (8认同)
  • 我绝对会对"这不值得"的心态提出质疑.如果您没有考虑谁"拥有"一个对象并负责它的生命周期,那么您将获得与对象CRUD相关的非常糟糕的代码,尤其是清理,当对象层次结构处于错误状态时,Null指针会飞来飞去. (2认同)

vsi*_*ngh 47

组合和聚合是关联的类型.它们密切相关,在编程方面没有太大的区别.我将尝试通过java代码示例解释这两者之间的区别

聚合:对象存在于另一个之外,在外部创建,因此它作为参数(例如)传递给construtor.例如:人 - 车.汽车是在不同的环境中创造的,然后成为人的财产.

// 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

构成:对象只存在,或者只在另一个内部有意义,作为另一个的一部分.例如:人 - 心.你不会创造一颗心,然后将它传递给一个人.

// 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”);
  }
}
Run Code Online (Sandbox Code Playgroud)

这里用一个例子来解释聚合和组合之间的区别

  • 到目前为止最好的答案之一。整洁:) (5认同)
  • 显示何时对象可以与(组合)或不与(聚合)其他对象一起存在的最佳Java代码示例. (5认同)

Dav*_*d M 36

组合意味着子对象与父对象共享生命周期.聚合没有.例如,国际象棋棋盘由国际象棋方块组成 - 国际象棋方块在没有棋盘的情况下并不存在.然而,汽车是零件的集合 - 如果汽车排气装置当时不是汽车的一部分,那么它仍然是汽车尾气.


Chr*_*sel 18

我学到的例子是手指.你的手是由手指组成的.它拥有它们.如果手死了,手指就会死亡.你不能"聚合"手指.你不能只是抓住多余的手指,随意地将它们从手上移开.

从设计的角度来看,这里的价值通常与对象的生命周期有关,正如另一张海报所说.假设您有一位客户并且他们有一个帐户.该帐户是客户的"组合"对象(至少在我能想到的大多数情况下).如果您删除了客户,则该帐户没有自己的价值,因此也会被删除.在对象创建方面通常是相反的.由于帐户仅在客户的上下文中具有意义,因此您将创建帐户作为客户创建的一部分(或者,如果您懒惰地执行,则它将成为某个客户交易的一部分).

在设计中考虑哪些对象拥有(组合)其他对象与仅引用(聚合)其他对象的对象是有用的.它可以帮助确定对象创建/清理/更新的责任.

就代码而言,通常很难说.代码中的大部分内容都是对象引用,因此引用的对象是组合(拥有)还是聚合可能并不明显.


Ger*_*ner 14

令人惊讶的是,关于部分 - 整体 - 关联概念聚合组合之间的区别存在多少混淆.主要问题是普遍的误解(即使是专家软件开发人员和UML的作者之间),构成的概念意味着整体与其各部分之间的生命周期依赖性,使得部分在没有整体的情况下不可能存在.但是这种观点忽略了这样一个事实,即存在与不可共享部分的部分整体关联的情况,其中部分可以与整体的分离分离并在其中存活.

在UML规范文档中,术语"组合"的定义总是暗示不可共享的部分,但尚不清楚"组合"的定义特征是什么,而仅仅是可选特征.即使在新版本(截至2015年),UML 2.5中,在尝试改进术语"组合"的定义之后,它仍然仍然含糊不清,并没有提供任何指导如何模拟与非组合的整体关联可分离的部件,其中部件可以从整体上拆下并经受损坏,而不是部件不能脱离并且与整体一起被破坏的情况.他们说

如果删除了复合对象,则会删除作为对象的所有零件实例.

但与此同时他们也说

在删除复合对象之前,可以从复合对象中删除部件对象,因此不会将其作为复合对象的一部分删除.

这种混淆指向UML定义的不完整性,该定义不考虑组件和组合之间的生命周期依赖性.因此,了解如何通过为" 不可分离的 "组合引入UML构造型来增强UML定义是很重要的,其中组件不能从它们的组合中分离,因此,每当它们的组合被销毁时都必须被销毁.

1)组成

正如Martin Fowler所解释的那样,表征构图的主要问题是"一个对象只能是一个构图关系的一部分".Geert Bellekens 的优秀博客文章UML Composition vs Aggregation vs Association也解释了这一点.除了组合物的这种定义特征(具有独占不可共享的部分)之外,组合物还可以在复合物与其组分之间具有生命周期依赖性.实际上,有两种这样的依赖:

  1. 每当组件必须始终连接到复合材料上,或者换句话说,当它具有强制复合材料时,如在组合线的复合面上的"恰好一个"多重性所表示的那样,则必须重新使用它在其当前复合材料被销毁时(或重新附加)另一个复合材料或被销毁.这可以通过下图中所示的Person和之间的组合来举例说明Heart.当一个人的主人已经死亡时,心脏会被摧毁或移植到另一个人身上.
  2. 每当组件不能从其复合材料中分离出来,或者换句话说,当它不可分离时,那么,只有这样,组件必须在其复合材料被销毁时被销毁.与不可分割的一部分这样的组合物的一个例子是间的组合物PersonBrain.

在此输入图像描述

总之,生命周期依赖性仅适用于特定的组合情况,但一般而言,它们不是一个定义特征.

UML规范声明:"在删除复合实例之前,可以从复合实例中删除部件,因此不会将其作为复合实例的一部分删除." 在Car- Engine组合的例子中,如下图所示,显然情况是在汽车被摧毁之前发动机可以从汽车上拆下,在这种情况下发动机不会被破坏并且可以重新使用.这由组合线的复合面上的零或一个多重性暗示.

在此输入图像描述

复合边的组合物关联结束的多重性是1或0..1,这取决于组件是否具有强制复合(必须连接到复合材料)的事实.如果组件是不可分割的,这意味着它们具有强制性组合.

2)聚合

聚合是与部分 - 整体关系的预期含义相关联的另一种特殊形式,其中整体的各部分可以与其他整体共享.例如,我们可以模型中的类之间的聚集DegreeProgramCourse,如下面的图中,由于过程是一定程度的程序的一部分,并且一个疗程可以在两个或更多的程度的程序之间共享(例如,工程度可以共享一个C具有计算机科学学位的编程课程).

在此输入图像描述

然而,具有可共享部分的聚合的概念并不意味着真的,因此它对实现没有任何影响,因此许多开发人员不喜欢在他们的类图中使用白色菱形,而只是模拟一个简单的关联代替.UML规范说:"共享聚合的精确语义因应用领域和建模者而异".

整个侧面的聚合关联结束的多样性可以是任何数字(*),因为部分可以属于任何数量的整体,或者在任何数量的整体之间共享.

  • 组合与生命周期并不严格相关,但在大多数现实问题中,生命周期是您组成或聚合的主要动机.我在答案中做了对冲,说生命周期"经常"相关,而不是总是相关.值得注意的是生命周期不是必需的,但是声明该视图是一个"主要问题"而且错误(用漂亮的粗体字体)让我感到无益,并且有损于指出实际使用注意事项. (2认同)

小智 8

在代码术语中,组合通常建议包含对象负责创建组件*的实例,并且包含对象保存对它的唯一长期引用.因此,如果父对象被取消引用并被垃圾收集,那么孩子也将如此.

所以这段代码......

Class Order
   private Collection<LineItem> items;
   ...
   void addOrderLine(Item sku, int quantity){
         items.add(new LineItem(sku, quantity));
   }
}
Run Code Online (Sandbox Code Playgroud)

表明LineItem是Order的一个组件 - LineItems在其包含顺序之外不存在.但Item对象不是按顺序构建的 - 它们是根据需要传递的,并且继续存在,即使商店没有订单.所以它们是关联的,而不是组件.

*nb容器负责实例化组件,但它实际上可能不会调用new ...()本身 - 这是java,通常首先要经过一两个工厂!