内部对象实例化的组合最佳实践

Composition best practice with internal object instantiation

我正在研究作文,有一个问题。假设我有一个 FruitApple 类,其中 apple 是水果

的直通
public class Apple {
    Fruit fruit;
}

Fruit 有一堆成员字段,例如skincolor 等。当我们实例化一个Apple 对象时,最佳实践是什么?我是否应该在内部构造 fruit 对象而不暴露 Apple 包含 Fruit 对象的任何迹象?即在构造 Apple 对象时,我调用 apple.setColor() 来在内部设置 fruit.setColor() 属性。或者,我应该构造完整的 fruit 对象并在 apple 实例化期间传入完全构造的 fruit 对象吗?

一个苹果里面有一个水果看起来很奇怪。在这种情况下我会使用继承。或者至少让 Apple 实现一个 Fruit 接口并隐藏委托成员。因此,对于构建 Fruit 成员,这意味着:在 Apple 构造函数内部执行。这是因为 Apple 和 Fruit 概念之间存在 is-a 关系。

在其他情况下,在构造函数中为成员传递预构造的实例可能会有用。情况就是这样,例如如果更多苹果指的是同一个水果实例。一般来说,Apple 和 Fruit

之间更像是 has-a 或 uses 关系

这实际上取决于您如何为问题建模。但是我认为关注 OOP 的 encapsulation 原则会对我们有所帮助。封装希望我们将有关对象的信息隐藏在自身内部,或者换句话说,让每个对象负责执行自己的操作。

回到你的问题,首先让我们考虑 Fruit 对象只是一个底层数据结构的情况(即 Apple 对象是 Fruit 在职责上的完整超集).在这种情况下,如果您要求开发人员为您构造 Fruit 对象并传递它,您就是在暴露您的内部责任,并且您可能会让开发人员访问不需要的数据或行为。

Fruit f = new Fruit();
f.doSomethingPrivate(); // This is not intended for an Apple to be set externally

Apple a = new Apple(f); // Now the Fruit object may not comply with Apple definition

现在很明显,在某些情况下,上面的示例正是您想要做的事情。现在考虑组合模式(参见 here)。在组合中,您有一个 容器,预计不会封装其所含元素的职责。

一个非常简单的例子可以是一门大学课程,其中一些学生注册并有一位讲师:

public class Course {
    private Person instructor;
    private Person[] students;
}

在这里,暴露教师或学生的行为不是 Course 对象的责任。相反,容器对象可能有 getInstructor()setInstructor() 方法,让开发人员决定组合中包含的元素。