继承与组合?

时间:2010-12-05 05:55:00

标签: 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的方法被委托给Apple作为继承。我的问题出现了:

  • 使用包装方法从Fruit委托方法,是不是促进了复制和粘贴,这是一种不好的做法?如果我们在Fruit中有大约10-50个方法的图像。如果有大约50个子类要继承,怎么能通过组合继承?

  • 关于第一个例子,通过使用扩展继承,作者建议超类中的一个更改将破坏使用它的实现。但是,我想知道,为什么需要改变?是否OO原则之一“关闭修改,开放延伸”?在作者声明的情况下,我仍然可以保留旧的超类实现,并仍然使其适应新的更改。像这样:

    类水果{

    // 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();
    }
    

    }

向超类添加新方法以适应而不是更改或替换旧方法是否有问题,这会破坏程序结构?据我所知,通过这样做,我仍然可以实现与组合示例相同的事情,并且我不必为很多子包的方法来为每个子类委托超类的方法。

  • 由于上述原因,我自己总结说,当有多个遗产时,或者当我需要分享不同且不属于一个阶级家庭的行为时,使用构图的唯一时间会更好。例如:

界面谈话{

 public void talk();

}

Animal class family可以实现Talkative接口以及Person类系列。您如何看待我的结论?

1 个答案:

答案 0 :(得分:3)

基本上,您似乎试图通过创建包装类来避免更改依赖于旧API的客户端。

不幸的是,这种方法效果不佳。它导致包装类的增加,以及其他的创建包装类的实例。如果你做了很多这样的事情,你的代码库/应用程序会变得臃肿,性能会受到影响,而且你的代码越来越难以理解。

更好的方法是:

  • 首先尝试正确使用API​​。 (咄!)
  • 如果API更改没有增加重要价值或修复重要内容,请推迟制作。
  • 当您确实需要进行API更改时,请以二进制兼容的方式进行;例如添加新方法,而不是对现有方法进行二进制不兼容的更改。如果您打算删除它们,请将旧方法标记为已弃用。
  • 进行二进制不兼容的API更改时,请同时更改所有使用它的代码。

@Deprecated标签允许您向人们发送API,警告不再使用某个方法,同时为他们提供一个窗口,用于修复其代码以使用替换方法/替代方法。