Java软件工程:组合与聚合



我真的很难理解Composition和Aggregation。在下面的代码中,我想知道以下哪个汽车实例使用了组合逻辑或聚合逻辑。

public class Engine {
public Engine() {
}
}
public class Car1 {
public final Engine engine;
public Car1() {
engine = new Engine();
}
}
class Car2{
public Engine engine;
public Car2(Engine engine) {
this.engine = engine;
}
}
class Car3{
public final Engine engine;
public Car3(Engine engine) {
this.engine = engine;
}
}
class Car4{
Engine engine;
public Car4(){
this.engine = new Engine();
}
}

class Main{
public static void main(String[] args) {
Engine engine = new Engine(); 
Car1 car1 = new Car1(); 
Car2 car2_1 = new Car2(new Engine());
Car2 car2_2 = new Car2(engine);
Car3 car3_1 = new Car3(new Engine());
Car3 car3_2 = new Car3(engine);
Car4 car4_1 = new Car4();
}
}

根据我的说法,car1,car2_1,car3_1遵循复合逻辑。但我在很多地方读到car3_2也是作文。为什么?如果我们销毁car3_2,仍然存在引擎实例,所以应该是聚合。

  • 聚合意味着子级可以独立于父级存在的关系。示例:班级(家长(和学生(孩子(。删除班级,学生仍然存在
  • 组合意味着孩子不能独立于父母而存在的关系。示例:House(父对象(和Room(子对象(。房间不与房子分开

因此,从本质上讲,对于以下任何对象,它都不能是Composition:

  • 可以由多个其他对象拥有
  • 可以无主(初始化完成后(
  • 可以更改所有者

car3_2不能是Composition,因为它与car2_2共享引擎。

其他的都是作文吗?从逻辑上讲,在现实生活中,你可以从一辆车上取下发动机,然后将其安装在另一辆车中,因此车与发动机的关系是聚合。

从程序上讲,final关键字阻止从Car中删除Engine,但它不会阻止同一个发动机添加到另一辆车上,也不会阻止汽车被"删除"和发动机更换所有者,因此final本身并不能确保Composition关系。

当构造函数将引擎作为参数时,Car类不能确保引擎不共享,因此不能确保Composition关系。

只有当Engine是由Car构造函数创建的,并且字段是final(或者实际上是最终的,本质上是没有setter方法的private(时,才能保证Composition的定义得到遵守。

这并不意味着其他以Engine为参数的方法不能有效地合成。这取决于它的使用方式。例如,如果Car是由Factory类创建的,则工厂可以强制执行组合规则。

是的,引擎仍然存在于car3_2实例之外,所以应该是Aggregation。

我想在Java中很难看出差异,因为对于任何对象,你只能存储对某个堆位置的引用,而在C++等其他编程语言中,你可以选择一个对象持有对另一个对象的引用,还是一个对象拥有该对象的嵌入副本。

但我们在java中,着眼于生命周期。。。。发动机是否会比汽车存在更长的时间取决于是否有人引用了该发动机。除car4外,所有汽车都有一个公开的发动机领域,任何人都可以获取并保留参考,从而在扔掉汽车时保留发动机。

我更希望car4没有包(默认(,甚至是私人访问。这意味着没有人应该访问该引擎引用(除非它在其他地方泄露(,你可以谈论Composition。

编辑:把你的问题和代码样本重读到底,我认为问题是关于它们是如何构建的。Car1和car4_1确实有自己隐含创建的引擎,当没有人获取引用时,汽车和引擎同时被收集垃圾。我称之为这篇作文。

Car2_1和car3_1的行为是相同的,尽管引擎是明确构建的。他们会用各自的引擎收集垃圾。这种行为类似,但也允许使用下一个模式。我猜它是作为诱饵引入的。

Car2_2和car3_2都共享一个显式创建的引擎,对它的引用出现在主方法中。其中一辆或两辆车可能会被收集垃圾,但除非三辆车都被放弃,否则发动机会一直存在。所以这可能应该显示聚合。

最新更新