聚合与组合

时间:2009-04-09 16:10:37

标签: java oop uml

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

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

12 个答案:

答案 0 :(得分:88)

根据经验: enter image description here

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

class City {
    private List<Tree> trees;
    private List<Car> cars
}

在作文中(人,心,手),一旦人被摧毁,“子对象”(Heart,Hand)将被销毁。

聚合(城市,树木,汽车)当城市被摧毁时,“子对象”(树,汽车)不会被销毁。

最重要的是,组合强调相互存在,而在聚合中,此属性不是必需的。

答案 1 :(得分:83)

聚合和组合之间的区别取决于背景。

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

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

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

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

答案 2 :(得分:43)

组合和聚合是关联的类型。它们密切相关,在编程方面没有太大的区别。我将尝试通过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;
  }
}

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

// 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”);
  }
}

此处使用示例Difference between Aggregation and Composition

进行了解释

答案 3 :(得分:36)

组合意味着子对象与父对象共享生命周期。聚合没有。例如,国际象棋棋盘由国际象棋方块组成 - 国际象棋方块在没有棋盘的情况下并不存在。然而,汽车是零件的集合 - 如果当时车辆不属于汽车,汽车尾气仍然是汽车尾气。

答案 4 :(得分:18)

我学到的例子是手指。你的手是由手指组成的。它拥有它们。如果手死了,手指就会死亡。你不能“聚合”手指。你不能只是抓住额外的手指,随意地将它们从手上移开并分开。

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

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

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

答案 5 :(得分:13)

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

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

  

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

但与此同时他们也说

  

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

这种混淆指向UML定义的不完整性,它不考虑组件和组合之间的生命周期依赖性。因此,了解如何通过为&lt;&lt; 不可分割 &gt;&gt;&gt;引入UML构造型来增强UML定义是非常重要的。组分不能从其复合材料中分离出来,因此,只要复合材料被破坏,就必须将其破坏。

1)组合物

作为Martin Fowler has explained,表征构图的主要问题是&#34;对象只能是一个构图关系的一部分&#34;。 Geert Bellekens在优秀博客文章UML Composition vs Aggregation vs Association中也对此进行了解释。除了组合的这种定义特征(具有 独占 ,或 不可共享 ,部分),组合物也可能在复合材料及其组件之间具有生命周期依赖性。实际上,有两种这样的依赖:

  1. 每当组件 必须始终附加 到组合时,或者换句话说,当它具有 必需组合,正如&#34;正好一个&#34;在组合线的复合面上具有多重性,然后当它的当前复合材料被破坏时,它必须在另一个复合材料中重复使用(或重新附着),或者被破坏。这可以通过PersonHeart之间的组合来举例说明,如下图所示。当一个人的主人去世时,心脏会被摧毁或移植到另一个人身上。
  2. 每当组件 无法脱离 时,或者换句话说, 不可分割时 strong>,然后,只有这样,当组件被销毁时,组件必须被销毁。这种具有不可分割部分的组合物的示例是PersonBrain之间的组合。
  3. enter image description here

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

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

    enter image description here

    复合方面的合成关联结尾的 多样性 是1或0..1,具体取决于组件是否具有强制性复合材料(必须附着在复合材料上)或不复合。如果组件不可分割,这意味着它们具有强制复合。

    2)聚合

    聚合是与部分 - 整体关系的预期含义相关联的另一种特殊形式,其中整体的各个部分可以与其他整体共享。例如,我们可以在类DegreeProgramCourse之间建模聚合,如下图所示,因为课程是学位课程的一部分,课程可以在两个或更多学位之间共享课程(例如工程学位可以与计算机科学学位共享C编程课程)。

    enter image description here

    然而,使用 可共享部分 进行聚合的概念并不是很重要,所以它对实现和许多开发人员没有任何影响因此,不要在类图中使用白色菱形,而只是建立一个普通的关联模型。 UML规范说:&#34;共享聚合的精确语义因应用领域和建模者而异。

    整个聚合关联端的 多样性 可以是任意数字(*),因为某个部分可能属于,或 分享 之间,任意数量的整体。

答案 6 :(得分:7)

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

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

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

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

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

答案 7 :(得分:0)

其他答案中提供的概念性插图很有用,但我想分享另一个我觉得有用的观点。

我已经从UML中获得了一些代码生成,源代码或关系数据库的DDL。在那里,我使用组合来表示一个表在我的代码中有一个不可为空的外键(在数据库中),以及一个不可为空的“父”(通常是“最终”)对象。我使用聚合,我希望记录或对象能够作为“孤儿”存在,不附加到任何父对象,或被另一个父对象“采用”。

换句话说,我使用合成符号作为简写来暗示在为模型编写代码时可能需要的一些额外约束。

答案 8 :(得分:0)

我喜欢的例子: 的成分: 水是池塘中的一部分。 (池塘是水的组成。) 的聚合: 池塘鸭子和鱼(池塘聚集鸭子和鱼)

正如你所看到的,我加粗了“part-of”和“has”,因为这两个短语通常可以指出类之间存在什么样的联系。

但正如其他人所指出的那样,很多时候连接是组合还是聚合取决于应用程序。

答案 9 :(得分:0)

在聚合关系和复合关系之间做差异是如此困难,但我将采取一些例子, 我们有一个房子和房间,在这里我们有一个复合的关系,房间是房子的一部分,房间生活从房屋生活开始,将在房屋生活结束时完成,房间是房子的一部分,我们谈论组成,像国家和资本,书籍和页面。 对于聚合关系的例子,采取团队和球员,球员可以在没有球队的情况下存在,球队是一组球员,球员生活可以在球队生活之前开始,如果我们谈论编程,我们可以创建球员,在我们创建球队之后,但是对于作品no,我们在屋内创造房间。 组成----&gt;复合|组成。 聚合-------&gt;小组|元件

答案 10 :(得分:0)

让我们设定条款。 Aggregation是UML标准中的元项,意味着BOTH组合和共享聚合,简称为 shared 。通常它被错误地命名为“聚合”。它是坏的,因为组合也是聚合。据我了解,您的意思是“共享”。

进一步来自UML标准:

  

composite - 表示属性是复合聚合的,   即复合对象对存在和存在负责   存储组合对象(部分)。

所以,大学到cathedras协会是一个组合,因为大学(IMHO)不存在大教堂

  

共享聚合的精确语义因应用领域而异   建模器。

即,如果您只遵循您或其他人的某些原则,则可以将所有其他关联绘制为共享聚合。另请查看here

答案 11 :(得分:0)

考虑肾脏,肝脏,大脑等人体部位。 如果我们尝试在这里映射组合和聚合的概念,那就像是:

在肾脏和肝脏等身体部位移植出现之前,这两个身体部位与人体组成,不能与人体隔离。

但是在身体部位移植出现后,它们可以移植到另一个人体内,因此这些部分与人体聚集在一起,因为它们与人体隔离存在是可能的。