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

Java 具有内部对象实例化的组合最佳实践,java,inheritance,composition,Java,Inheritance,Composition,我在玩弄作文,有个问题。假设我有一个水果和苹果类,其中苹果是水果的传递 public class Apple { Fruit fruit; } 水果有一系列成员字段,如皮肤,颜色等。当我们实例化苹果对象时,最佳做法是什么?我是否应该在内部构造水果对象,而不暴露苹果包含水果对象的任何迹象?i、 e.在构造Apple对象时,我调用Apple.setColor(),它在内部设置fruit.setColor()属性。或者,我是否应该构造完整的水果对象,并在苹果实例化过程中,传入完整构造的水果对

我在玩弄作文,有个问题。假设我有一个
水果
苹果
类,其中
苹果
是水果的传递

public class Apple {
    Fruit fruit;
}

水果有一系列成员字段,如
皮肤
颜色
等。当我们实例化
苹果
对象时,最佳做法是什么?我是否应该在内部构造
水果
对象,而不暴露苹果包含水果对象的任何迹象?i、 e.在构造Apple对象时,我调用
Apple.setColor()
,它在内部设置
fruit.setColor()
属性。或者,我是否应该构造完整的
水果
对象,并在
苹果
实例化过程中,传入完整构造的
水果
对象?

在苹果中有水果似乎很奇怪。在这种情况下,我将使用继承。或者至少让Apple实现一个Fruit接口并隐藏代理成员。对于构建水果成员,这意味着:在Apple构造函数内部进行。这是因为苹果和水果概念之间的关系


在其他情况下,在构造函数中为成员传递预构造的实例可能会很有用。如果更多的苹果引用同一个水果实例,情况就是如此。一般来说,这更多的是苹果和水果之间的has-a或uses关系,这实际上取决于你如何建模你的问题。但我认为关注OOP的封装原理会对我们有所帮助。封装希望我们隐藏对象本身的信息,或者换句话说,让每个对象负责执行自己的操作

回到你的问题,首先让我们考虑以下的情况:<代码>水果>代码>对象只是一个底层的数据结构(即<代码> Apple < /Cord>对象是一个完整的超集:代码>水果<代码>职责中)。在这种情况下,如果您要求开发人员为您构建

水果
对象并将其传递给您,那么您就暴露了您的内部责任,您可能会让开发人员访问不需要的数据或行为

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
现在很明显,在某些情况下,上面的示例正是您想要做的事情。现在考虑构图模式(见)。在组合中,您有一个容器,该容器预期不会封装其所包含元素的职责

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

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

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

为什么您首先希望苹果中有一个水果对象?这只是一个人为的例子,只是在我的问题周围有一些上下文。本质上可以归结为:如果我的外部类中有另一个类的实例,那么最好的做法是在内部或外部配置它。例如,在我的Apple类中,我的颜色Apple.setColor(红色)的setter基本上会在Apple类Apple.getColor中设置水果。setColor(红色)和颜色的getter()将返回水果。getColor()?我之前的评论不准确。在设计Apple类时,通过Apple构造函数将整个水果传递给Apple应该是更好的方法。除非您希望您的Apple更改颜色,否则setter不是一个好主意。从这里得到了这个想法: