我通过Java World中的文章做了一些关于作文的阅读: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();
}
}
修改后,它不再适用:
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();
}
}
稍后它可以通过接口执行polymorph:请参阅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);
}
}
密钥不是继承,而是创建超类的新实例。而不是传统的多态性。据说使用这种方法比继承更好,因为继承被破坏了。
编辑:稍后,如果我们希望水果变成不同类型而不是Apple,我们可以这样做:
class Banana implements Peelable {
private Fruit fruit = new Fruit();
public int peel() {
return fruit.peel();
}
}
这是多态性如何通过组合完成的。因此,如果一个方法需要一个可以剥离的水果,我们只需要将Peelable对象传递给它而不是水果。
请阅读第3个答案。我为这个主题添加了更多信息。
答案 0 :(得分:4)
如果你要征求意见,我就要说:
通过组合进行的继承不一定更好,也不一定比通过extends
的严格继承更糟糕。它们完全用于不同的目的。
组合的一个好处是它允许在API中使用更有限的一组潜在操作 - 例如,可以定义一个Stack
类来继承LinkedList
,但添加一个{{ 1}}和push()
方法。但是,没有办法通过调用pop()
或add(elem, 4)
之类的东西来阻止客户端代码滥用堆栈,从而绕过堆栈。作文解决了这个问题。
然而,扩展课程也有其好处。例如,假设你要制作一个get(5)
,但你不想要任何整数&lt; 0.如果您在Stack<Integer>
中包含Stack
,那么您必须包含方法GreaterThanZeroStack
,push()
,pop()
以及其他任何方法是正确操作所必需的。这会产生许多不必要的样板重复代码。如果您向堆栈添加另一个方法(如peek()
),它还会创建不必要的维护。如果您扩展punch()
,则只需覆盖一个方法 - Stack
。此外,您现在可以将其声明为add(Integer i)
,或将其传递给接受参数Stack<Integer> s = new GreaterThanZeroStack()
的方法。你可以用作文来做这件事吗?没机会。
组合和扩展有两个完全不同的目的,组合的继承不一定是要遵循的模式。
在你的案例中,按扩展名继承是正确的。苹果是一种水果。苹果不含水果。如果您要向Fruit添加另一种方法,例如Stack s
,那么Apple会免费获得该方法,而对于组合,Apple必须重新实现该方法,如下所示:
public int weight() { return fruit.weight(); }
然后每次更改重量时都会更改,例如返回类型或名称。
答案 1 :(得分:1)
一个重要的考虑因素是,通过构图,你会失去“is-a”关系。复合水果的苹果不是水果,不能传递给需要水果的方法。
并不是说继承被破坏了,只是它被过度使用和误用了。
关于使用多态接口的评论中的要点很好。如果您完全可以控制,则可以使用界面和组合构建整个系统。你可能最应该 - “更喜欢构图而不是继承”。
但是,它“更喜欢......结束”,而不是“替换......”。在某些情况下,某些东西的合理公共接口太大而无法为所有内容编写传递包装方法。我可以想到我编写的一个GUI工具包,它有6个代表GUI系统核心部分的顶级抽象类 - 它们绝对是使用继承而不是接口正确设计的。基本组件具有大约120种方法的大型公共接口。我肯定不会想要一个接口,然后在每个单独的具体组件中实现120个包装器方法。
答案 2 :(得分: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;
}
}
这是多重继承的想法,我可以在阅读完文章后提出来。你怎么看?
我在问,因为当我第一次学习编程时,它总是通过扩展来继承。现在,正如我所听到的,我的同学们说赞成作文,即使在继承的情况下,也比使用扩展的继承概念更好。因此,组合应该优于继承,另一个原因是它接近函数式编程。我只想听到不同意见。