一个月前我问过类似的问题:Inheritance though composition?
我从这篇文章中获取了示例:http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html?page=1 然而,这一次是一个不同的问题。抱歉,贴了很多代码,但代码很长,阅读起来并不困难。
class Fruit {
public int peel() {
System.out.println("Peeling is appealing.");
return 1;
}
}
class Apple extends Fruit {
}
class Example1 {
public static void main(String[] args) {
Apple apple = new Apple();
int pieces = apple.peel();
}
}
修改后就不行了:
class Peel {
private int peelCount;
public Peel(int peelCount) {
this.peelCount = peelCount;
}
public int getPeelCount() {
return peelCount;
}
}
修改 Fruit 类会导致编译错误代码。
class Peel {
private int peelCount;
public Peel(int peelCount) {
this.peelCount = peelCount;
}
public int getPeelCount() {
return peelCount;
}
}
class Fruit {
// Return a Peel object that
// results from the peeling activity.
public Peel peel() {
System.out.println("Peeling is appealing.");
return new Peel(1);
}
}
旧的实现已被破坏。该问题可以通过组合来解决:
class Peel {
private int peelCount;
public Peel(int peelCount) {
this.peelCount = peelCount;
}
public int getPeelCount() {
return peelCount;
}
}
class Fruit {
// Return int number of pieces of peel that
// resulted from the peeling activity.
public Peel peel() {
System.out.println("Peeling is appealing.");
return new Peel(1);
}
}
// Apple must be changed to accomodate
// the change to Fruit
class Apple {
private Fruit fruit = new Fruit();
public int peel() {
Peel peel = fruit.peel();
return peel.getPeelCount();
}
}
// This old implementation of Example2
// still works fine.
class Example1 {
public static void main(String[] args) {
Apple apple = new Apple();
int pieces = apple.peel();
}
}
从构图风格来看,苹果与Fruit不再是is-关系。它变成了has-a。 Fruit 中的方法作为继承委托(delegate)给 Apple。我的问题出现了:
使用包装方法来委托(delegate) Fruit 的方法,这不是会促进复制和粘贴,这是一种不好的做法吗?想象一下 Fruit 中有大约 10-50 个方法。如果有大约50个子类需要继承,怎么可能通过组合继承呢?
关于第一个示例,即使用扩展进行继承,作者建议父类(super class)中的一个更改将破坏使用它的实现。但我想知道,为什么需要改变呢? OO原则之一不是“对修改关闭,对扩展开放”吗?在作者所说的情况下,我仍然可以保留旧的父类(super class)实现并仍然使其适应新的变化。像这样:
水果类{
// Return a Peel object that // results from the peeling activity. private Peel getPeel() { System.out.println("Peeling is appealing."); return new Peel(1); } public int peel(){ Peel peel = getPeel(); return peel.getPeelCount(); }
}
在父类(super class)中添加新方法来适应而不是改变或替换旧方法,会破坏程序结构,这是否有问题?据我所知,通过这样做,我仍然可以实现与组合示例相同的效果,而且我不必制作大量包装方法来为每个子类委托(delegate)父类(super class)的方法。
- 由于上述原因,我得出的结论是,只有当存在多重继承时,或者当我需要共享变化且不属于一个类族的行为时,才使用组合会更好。例如:
界面健谈{
public void talk();
}
Animal类家族可以实现Talkative接口(interface)以及Person类家族。您觉得我的结论怎么样?
最佳答案
基本上,您似乎试图通过创建包装类来避免更改依赖于旧 API 的客户端。
不幸的是,这效果不太好。它导致包装类的激增,以及创建包装类实例的其他麻烦。如果您这样做太多,您的代码库/应用程序会变得臃肿,性能受到影响,并且您的代码会变得越来越难以理解。
更好的方法是:
- 首先尝试正确使用 API。 (呃!)
- 如果 API 更改没有增加显着值(value)或修复重要问题,请推迟更改。
- 当您确实需要更改 API 时,请以二进制兼容的方式进行;例如添加新方法而不是对现有方法进行二进制不兼容的更改。如果您打算摆脱旧方法,请将它们标记为已弃用。
- 当您必须更改二进制不兼容的 API 时,请同时更改使用它的所有代码。
@Deprecated 标记允许您向人们发出 API 警告,警告不应再使用某个方法,同时为他们提供一个窗口来修复其代码以使用替换方法/替代方法。
关于java - 继承与组合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4357589/