来自GoF的设计模式:
表示部分或聚合关系的对象引用为 用箭头表示,底部带有菱形。箭头指向 汇总的类(例如Shape)。没有钻石的箭头线 表示相识(例如LineShape保留对Color对象的引用,而其他 形状可以共享)。参考名称可能会出现在底座附近以区别 从其他参考 另一个有用的事情是实例化 其他的。我们使用虚线箭头表示这一点, 因为OMT不支持。我们称其为“创造” 关系。箭头指向实例化的类。在 图B.lc,CreationTool创建LineShape对象。
当对象A聚合对象B时,对象A是否必须具有引用对象B的字段成员?
当对象A认识对象B时,对象A是否必须具有引用对象B的字段成员?
当对象A实例化对象B时,对象A是否必须具有引用对象B的字段成员?
答案 0 :(得分:1)
实例化创建一个对象实例(许多语言为此使用new
关键字),而聚合描述了对象(已经创建或实例化)之间的关系。
为了避免混淆,我必须指出,在此示例中使用的所有术语,例如 aggregation ,都是在Martin Fowler的上下文中使用的,Martin Fowler引入了与UML标准定义不同的定义或措辞。 / p>
从图中:
根据您提供的图表,给出了两个类定义Drawing
和Shape
,它们之间的关系称为 aggregation ,根据定义,该关系描述了共享生存期。这意味着Drawing
“包含”任意数量的Shapes
,或更准确地说,Shape
是Drawing
的一部分。当所有者(Drawing
)的生存期结束时,Shape
的生存期也将终止:
// The `Shape` class
class Shape
{
...
}
// The `Drawing`class that aggregates a single `Shape`
class Drawing
{
// The reference to the instance of `Shape`
private Shape shape;
// The constructor
public Drawing()
{
// Create an instance of `Shape`.
// Because the relationship between `Drawing`and `Shape`is an aggregation the instantiation occurs inside the owners constructor (opposed to outside the owner object).
this.shape = new Shape();
}
}
因为Drawing
和Shape
之间的关系是聚集,所以类型Shape
的实例发生在内部 所有者构造函数(如果是相识,则与所有者对象相对)。
图中显示的另一个关系是相识。 相识存在于LineShape
类型和Color
类型的对象之间。这意味着LineShape
使用一个Color
。 Color
将独立于其拥有的LineShape
对象而生活。对象CreationTool
和LineShape
之间的虚线描述了实例化(创建)。这意味着CreationTool
创建LineShape
的实例。这是必需的,因为与 aggregation 熟人相对,它描述了两个对象的独立寿命。 Color
可以在其他Shape
对象之间共享。这要求LineShape
的相关对象Color
在所有者外部(而不是在 aggregation 场景中那样,不在所有者的构造函数内部)实例化:
// The `LineShape` class
class Color
{
...
}
// The `LineShape`class that acquaints or associates with a single `Color`
class LineShape
{
// The reference to the instance of `Shape`
private Color color;
// The constructor
public LineShape(Color sharedColorInstance)
{
// Request an instance of `Shape` as constuctor parameter.
// Because the relationship between `LineShape`and `Color`is an acquaintance the instantiation occurs outside the owners constructor (opposed to inside the owner object).
this.color = sharedColorInstance;
}
}
// The `CreationTool` class that creates an instance of `LineShape
// and passes a shared instance of `Color`into the constructor.
class CreationTool
{
Color color = new Color();
// Create the instance of `LineShape`
// to satisfy the dashed line (relationship) in the diagramm
LineShape firstLine = new LineShape(color);
// To show the benefit of acquaintance a second instance of `LineShape` is created
// using the same `Color` instance
LineShape secondLine = new LineShape(color);
// When firstLine's lifetime ends,
// secondLine still has a valid instance of `Color`
}
由于LineShape
和Color
之间的关系是认识,因此实例化发生在外部所有者构造函数(而不是在 aggregation 场景中在所有者对象内部)。这样,Color
的单个实例可以在多个所有者之间共享。
正如您在代码示例中看到的那样,两个关系(或一般关系) require 都指向要存储在拥有对象内部的指向相关对象的引用。唯一的区别是查看在何处创建拥有的对象。这种情况将描述这种关系的特殊形式:关联对象是实例化为所有者的 outside (熟人)还是实例化了所有者的 inside (聚合)? 这意味着您可以通过查看构造函数(或实例化)来区分这两种类型的关系:是传递给构造函数的相关对象实例,还是所有者的设置方法( acquaintance ),或者是所有者的构造函数少参数还是无设置数( aggregation )?
对于实例化,字段的要求是不同的故事。我们可以说,CreationTool
实例化LineShape
时,它不需要字段来存储对此对象的引用。但是对于Color
,CreationToolobject
可以将对Color
实例的引用存储在字段中,以便在创建新的LineShape
实例时重用(共享)它,因为需要Color
的实例才能满足LineShape
的构造函数。因此,如果首先需要一个用于在创建者内部存储对创建实例的引用的字段,则该字段完全是可选的,并且取决于上下文。
在这一点上应该提到,对于熟人,“注入”拥有对象实例的另一种方法是使用setter方法:
Color color = new Color();
LineShape shape = new LineShape();
shape.SetColor(color);
在可能的情况下,首选使用构造函数。
另一个说明,只是为了使其更加完整:当用于实现这种关系的语言具有自动内存管理(垃圾收集)时,生命周期控制方面就不再重要了。只要在M. Fowlers世界(或在UML世界的 aggregation )中,所有事物都成为熟人,因为只要存在对所拥有对象实例的任何引用(例如,公开实例(通过getter方法)),垃圾收集器不会破坏该实例,并且它将继续存在-独立于所有者。