java - 继承与组合?

标签 java design-patterns

一个月前我问过类似的问题: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/

相关文章:

java - 虽然我已经设置了actionListener,但是按下按钮时没有任何反应

java - 有多个可选参数

java - 如何获取android目录下的所有文件名?

java - 将变量放入 find.By CSS 但出现错误 : "Attribute value must be a constant" for Selenium/Java

java - 工资计算模式

sql - 存储库模式困境 : Redundant Queries vs. 数据库往返

java - 有这方面的模式吗?对某些子类具有特殊操作的通用基类

java - Jasper Reports - 从 Java 中的 BaseColumn 类获取详细对象详细信息

java - Head First 设计模式与 Head First 面向对象分析与设计

c++ - 如何构建加密库