2010-11-04 54 views
0

我做了一些阅读成分通过的Java世界的文章:http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html?page=1继承虽然组成?

在这篇文章中,它指导如何做到继承,而不使用extends关键字。我正在那样做。这可以吗?它似乎为我工作。

下面是代码:

的遗传代码的例子:第2页的文章\ 根据这篇文章,它工作正常:

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

修改后,它不再OK:

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

// Apple still compiles and works fine 
class Apple extends Fruit { 
} 

// This old implementation of Example1 
// is broken and won't compile. 
class Example1 { 

    public static void main(String[] args) { 

     Apple apple = new Apple(); 
     int pieces = apple.peel(); 
    } 
} 

现在通过组合物重用:

class Fruit { 

// Return int number of pieces of peel that 
// resulted from the peeling activity. 
public int peel() { 

System.out.println("Peeling is appealing."); 
     return 1; 
    } 
} 

class Apple { 

    private Fruit fruit = new Fruit(); 

    public int peel() { 
     return fruit.peel(); 
    } 
} 

class Example2 { 

    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; 
    } 
} 


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

后来它可以通过界面做的多晶型:见和javaworld 4页的“使用接口设计:”我不能在这里发布另一个链接。

interface Peelable { 

int peel(); 
} 

class Fruit { 

// Return int number of pieces of peel that 
// resulted from the peeling activity. 
public int peel() { 

System.out.println("Peeling is appealing."); 
      return 1; 
     } 
    } 

    class Apple implements Peelable { 

     private Fruit fruit = new Fruit(); 

     public int peel() { 
      return fruit.peel(); 
     } 
    } 

    class FoodProcessor { 

     static void peelAnItem(Peelable item) { 
      item.peel(); 
     } 
    } 

    class Example5 { 

     public static void main(String[] args) { 

      Apple apple = new Apple(); 
      FoodProcessor.peelAnItem(apple); 
     } 
    } 

关键是代替继承,我们创建了一个新的超类实例。而不是传统的多态。据说使用这种方法比继承更好,因为继承被打破了。

编辑:以后,如果我们想的水果晶型成不同的类型,而不是苹果公司,我们可以这样做:

class Banana implements Peelable { 

    private Fruit fruit = new Fruit(); 

    public int peel() { 
     return fruit.peel(); 
    } 
} 

这是怎么多态性是由组成完成。所以,如果一个方法需要一个可剥离的水果,我们只需要将Peelable对象传递给它而不是水果。

请阅读第3个答案。我为此主题添加了更多信息。

+0

你是什么意思“遗传被打破”?它有什么坏处? – Neowizard 2010-11-04 02:47:14

+1

''是的,这不是我的代码,是瘸子...它是继承是破产和单身,SUCK大的时间。 :P'' – rsenna 2010-11-04 03:11:06

+0

呃,对不起。我应该说清楚。它像Java一样通过扩展继承。请阅读下面的第三个答案了解更多详情。 – Amumu 2010-11-04 04:39:45

回答

4

如果你要求的意见,这是我不得不说:

继承通过成分不一定更好,不一定比通过extends严格继承恶化。他们完全是为了不同的目的。组成

一个好处是它允许一组更有限的API中潜在的操作 - 例如,一个可以定义一个类StackLinkedList继承,但增加一个push()pop()方法。但是,无法通过调用类似add(elem, 4)get(5)的方法来阻止客户端代码滥用您的堆栈,这会绕过堆栈。成分解决了这个问题。

但是,扩展类也有其好处。例如,假设你想制作一个Stack<Integer>,但你不想要任何整数< 0.如果你在GreaterThanZeroStack中包含Stack,那么你必须包括方法push(),pop(),peek()和其他任何其他是正确操作所必需的。这会产生大量不必要的,样板化的重复代码。如果你像punch()那样向你的堆栈中添加另一种方法,它也会造成不必要的维护。如果您改为Stack,那么您只需重写一个方法 - add(Integer i)。另外,您现在可以将其声明为Stack<Integer> s = new GreaterThanZeroStack(),或将其传递到接受参数Stack s的方法中。你可以用组合做这个吗?没有机会。

构图和扩展有两个完全分开的目的,并且通过构图的继承不一定是遵循的模式。


情况下,继承推而广之是正确的。一个苹果是一种水果。一个苹果不包含水果。如果您要添加另一种方法来水果,如weight(),那么苹果将获得的是免费的,而与组成,苹果不得不重新实现说类似的方法:

 
public int weight() { 
    return fruit.weight(); 
} 

,然后更改每时间改变了体重,就像它的返回类型或名字一样。

+0

我同意通过扩展继承减少开销代码。正如文章中解释的那样,通过组合的继承的一个好处是你可以通过一个接口进行编程。因此,如果您更改超类中的某个方法,那么正在使用它的代码将被打破。 – Amumu 2010-11-04 03:15:49

+0

但为什么如果你已经有一个“接口” - 以父类的形式 - 内置?看,为了扩展'JFrame',你想为每个公共方法有大量的代码吗?没有!首先,这是继承的要点 - 你不必! – 2010-11-04 03:18:57

+0

好点。我认为我们可以使用JFrame进行扩展的原因是因为它的实现对于人们使用它是不可改变的。它只能由其创建者进行更改。但是,对于我们自己的应用程序,软件总是在变化如果我们改变超类,它会影响整个应用程序。但是,这篇文章的原因是什么消除了“扩展”的用途:http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html?page=2 – Amumu 2010-11-04 05:08:19

1

一个重要的考虑因素是,用组合物可以减少“是 - 一个”关系。复合水果的苹果不是水果,不能传递给需要水果的方法。

这不是遗传被破坏,只是它被过度使用和滥用。

有关使用接口进行多态性的注释中的观点很有用。如果您完全控制,则可以使用界面和组合构建整个系统。你大概应该 - “更喜欢构图而不是继承”。

但是,它“比...更喜欢......”,而不是“替换......”。在某些情况下,某些东西的合理公共接口太大,无法为所有东西编写传递包装方法。我可以考虑一个我编写的GUI工具包,它有6个顶级抽象类,它们代表了GUI系统的核心部分 - 它们绝对正确地使用继承来设计,而不是接口。基本组件具有大约120多种方法的大型公共接口。我肯定不会想要一个接口,然后在每个具体组件中实现120个包装器方法。

+1

嗯,你仍然可以将它传递给需要Fruit的方法,通过实现一个通用接口。在我的文章中的例子中,作者使用接口可剥离来做多态。 – Amumu 2010-11-04 04:41:30

0

请看看这篇文章:http://www.javaworld.com/javaworld/jw-12-1998/jw-12-techniques.html

在第2页,有一个例子说明该钻石的问题,你不能从多个家长在Java中继承。

在文章中,作者通过接口来介绍Java中的多重继承。

此基础上,这里是我想出如何在Java多重继承会是什么样子:

interface Animal{ 
    public void getLegs(); 
} 

class Dinosour implements Animal{ 
    int legs=4; 
    public int getLegs(){ 
     return this.legs; 
    } 
} 

class Frogs implements Animal{ 
    int legs=2; 
    public int getLegs(){ 
     return this.legs; 
    } 
} 

class Frogosour implements Animal { 
    Dinosour father = new Dinosour(); 
    Frog mother = new Frog(); 
    int legs; 
    public int getLegs(){ 
     return (father.getLegs()+mother.getLegs())/2; 
    } 
} 

这是多重继承的理念贯穿文章看完之后我可以想出。你怎么看?

我在问,因为当我第一次学习编程时,它总是通过继承而被教导的。现在,正如我听到我的同学说,即使在继承的情况下,青睐组合也比使用扩展的继承概念更好。因此,组合应该比继承更受欢迎,另一个原因是它接近于函数式编程。我只想听到不同的意见。

+0

我喜欢这个例子! “Frogosaur”也应该实现“动物”,但你已经掌握了它。 – CurtainDog 2010-11-04 08:55:22

+0

谢谢。所以如果我想实现Frogosour的一个孩子(可能它有另一个Snake作为妻子),我只是实现了Frogosour的所有接口(包括它的父母的接口和它自己的方法的接口(孩子应该不同于他们的父母毕竟))以及Snake的界面。如果它有更多的孩子,那么进化就会继续。它最终是如何工作的? – Amumu 2010-11-04 12:12:23