面向对象的建模非常主观,但我唯一能做的就是旧的继承与组合讨论:
https://www.thoughtworks.com/insights/blog/composition-vs-inheritance-how-choose
根据您的论点,我相信您经常尝试从两个或多个具有相似代码的类中提取超类,这样它们就可以共享相同的继承方法,而不仅仅是复制它们。尽管从技术上讲,这正是您想要的,但您还应该注意继承语义,因为它将表示 is-a 关系(即,汽车 is-a 车辆,狗 is-a 哺乳动物,报告屏幕 is-a 只读屏幕)。由于 Java 不提供多重继承,如果您的类层次结构增长,您最终可能会受到限制和困惑。
因此,在开始提取超类以供重用之前,请记住,您也可以将这些 code-i-want-to-reuse 单元提取为 part-of其他类(作文)。
对不起,我的概念性示例,但在这里:
狗和狮子都是哺乳动物和猎人。它们应该自然地继承 Mammals 超类(在哺乳动物中有很多可重用的代码)。由于并非所有哺乳动物都会捕猎,因此我们不想在 Mammals 类上定义新的 hunt() 方法。
此时,您可能正在考虑创建一个新的继承级别:哺乳动物 。但想一想:如果你继续对动物的每一个独特方面都这样做,你将拥有几十个处于复杂和令人困惑的层次结构中的类。除此之外,我们也知道一些爬行动物和鸟类也会狩猎,所以,我们最好将所有狩猎的东西隔离在其他地方。
作为继承的健康替代方案,我们可以定义一个单独的 Hunter 类。要重用它的内容,我们需要做的就是将一个 Hunter 对象作为 Dog 和 Lion 的成员(一个字段)。如果我们需要将狗和狮子一起视为猎人(多态),我们可以定义一个 CanHunt 接口来对它们进行分组。
查看以下示例:
class Hunter {
void hunt(){
System.out.println("i'm hunting...");
}
}
interface CanHunt{
Hunter getHunter();
}
class Dog extends Mammals implements CanHunt{
...
Hunter hunter = new Hunter();
@Override
Hunter getHunter(){
return hunter;
}
...
}
class Lion extends Mammals implements CanHunt{
...
Hunter hunter = new Hunter();
@Override
Hunter getHunter(){
return hunter;
}
...
}
这里我们有一个多态示例代码,它要求狗和狮子都做它们的狩猎工作:
...
List<CanHunt> hunters = new LinkedList();
hunters.add(new Dog());
hunters.add(new Lion());
for(CanHunt h:hunters){
h.getHunter().hunt(); //we don't know if it's a dog or a lion here...
}
...
我希望这个简单的例子能给你一些启发。如果我们不断将其发展为更详细但更灵活的设计,它可能会变得相当复杂。例如,Hunter 类可以是具有不同实现的抽象类,因为狗的狩猎方式与狮子不同,但它们有一些共同的行为。