您应该使用接口(而不是继承)或某种属性机制(甚至可以像资源描述框架那样工作)。
所以要么
interface Colored {
Color getColor();
}
class ColoredBook extends Book implements Colored {
...
}
要么
class PropertiesHolder {
<T> extends Property<?>> Optional<T> getProperty( Class<T> propertyClass ) { ... }
<V, T extends Property<V>> Optional<V> getPropertyValue( Class<T> propertyClass ) { ... }
}
interface Property<T> {
String getName();
T getValue();
}
class ColorProperty implements Property<Color> {
public Color getValue() { ... }
public String getName() { return "color"; }
}
class Book extends PropertiesHolder {
}
澄清(编辑):
只需在实体类中添加可选字段
尤其是对于Optional-wrapper(编辑:请参见4castle的答案),我认为这(在原始实体中添加字段)是一种小规模添加新属性的可行方法。这种方法的最大问题是它可能会抑制低耦合。
想象一下,您的书类是在针对您的域模型的专用项目中定义的。现在,您添加了另一个使用域模型执行特殊任务的项目。此任务在book类中需要一个附加属性。您要么获得继承(参见下文),要么必须更改公共域模型以使新任务成为可能。在后一种情况下,您可能最终得到一堆全部依赖于添加到book类的属性的项目,而book类本身以某种方式依赖于这些项目,因为没有这些,您将无法理解book类。其他项目。
为什么在提供其他属性的方式上继承会引起问题?
当我看到示例类“书”时,我想到的是一个域对象,该对象通常最终具有许多可选字段和子类型。试想一下,您想为包含CD的书籍添加属性。现在有四种书籍:书籍,彩色书籍,带CD的书籍,彩色和 CD的书籍。您无法用Java中的继承描述这种情况。
使用接口可以避免此问题。您可以通过接口轻松地组成特定书籍类的属性。委托和撰写将使您轻松获得所需的课程。对于继承,您通常会在类中最终得到一些可选属性,因为它们是同级类所需要的。
进一步阅读为什么继承通常是一个有问题的想法:
为什么OOP支持者通常将继承视为一件坏事
JavaWorld:为什么扩展是邪恶的
实现一组接口以组成一组属性的问题
当您使用接口进行扩展时,只要您只有一小部分接口就可以了。特别是当您的对象模型被其他开发人员使用和扩展时,例如在您公司中,接口的数量将会增加。最终,您最终创建了一个新的正式“属性接口”,为您的同事添加了一种方法,该方法已经在您的同事中为客户X使用,用于一个完全不相关的用例-Ugh。
编辑:gnasher729提到了另一个重要方面。您通常希望将可选属性动态添加到现有对象。使用继承或接口,您将不得不使用另一个非可选类来重新创建整个对象。
当您期望对对象模型进行扩展时,可以通过对动态扩展的可能性进行显式建模来更好。我提议类似上面的内容,其中每个“扩展”(在本例中为属性)都有自己的类。该类用作扩展名的名称空间和标识符。相应地设置包命名约定时,这种方式允许无限数量的扩展,而不会污染原始实体类中方法的名称空间。
在游戏开发中,您经常会遇到想要组合多种变化的行为和数据的情况。这就是为什么架构模式实体-组件-系统在游戏开发界非常受欢迎的原因。当您期望对象模型有许多扩展时,这也是您可能想研究的一种有趣的方法。