组合和继承是一样的吗? 如果我想实现组合模式,我如何在Java中做到这一点?


当前回答

继承带来IS-A关系。复合引出HAS-A关系。 策略模式解释了组合应该用于定义特定行为的算法族的情况。典型的例子是实现飞行行为的鸭子类。

public interface Flyable{
 public void fly();
}

public class Duck {
 Flyable fly;

 public Duck(){
  fly = new BackwardFlying();
 }
}

因此,我们可以有多个实现飞行的类 例如:

public class BackwardFlying implements Flyable{
  public void fly(){
    Systemout.println("Flies backward ");
  }
}
public class FastFlying implements Flyable{
  public void fly(){
    Systemout.println("Flies 100 miles/sec");
  }
}

如果是继承的话,我们就会有两个不同的鸟类,它们会反复实现fly函数。所以继承和组合是完全不同的。

其他回答

另一个例子,考虑一个汽车类,这将是一个很好的组合使用,一个汽车将“有”一个发动机,一个变速器,轮胎,座位,等等。它不会扩展任何这些类。

合成就像它听起来一样-你通过插入部分来创建一个对象。

这个答案的其余部分错误地基于以下前提。 这是通过接口完成的。 例如,使用上面的Car例子,

Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel

用一些标准的理论组件,你就可以构建你的对象。然后,你的工作就是填写房子如何保护它的居住者,以及汽车如何保护它的居住者。

继承则正好相反。您从一个完整(或半完整)对象开始,然后替换或覆盖您想要更改的各种位。

例如,机动车辆可能带有可燃料方法和驱动方法。您可以保留Fuel方法,因为给摩托车和汽车加油是一样的,但您可以重写Drive方法,因为摩托车的运行方式与汽车非常不同。

通过继承,一些类已经完全实现,而其他类的方法必须重写。在合成中什么都没有给你。(但是你可以通过调用其他类中的方法来实现接口,如果你碰巧有一些东西的话)。

组合被认为是更灵活的,因为如果你有一个像iUsesFuel这样的方法,你可以在其他地方有一个方法(另一个类,另一个项目),它只关心处理可以被燃料的对象,不管它是汽车、船、炉子、烧烤等等。接口要求那些声称实现了该接口的类实际上拥有该接口的全部方法。例如,

iFuelable Interface:
   void AddSomeFuel()
   void UseSomeFuel()
   int  percentageFull()

然后你可以在其他地方有一个方法

private void FillHerUp(iFuelable : objectToFill) {

   Do while (objectToFill.percentageFull() <= 100)  {

        objectToFill.AddSomeFuel();
   }

奇怪的例子,但它表明这个方法并不关心它在填充什么,因为对象实现了iUsesFuel,它可以被填充。故事结束了。

如果你使用继承,你将需要不同的FillHerUp方法来处理机动车辆和烧烤,除非你有一些相当奇怪的“ObjectThatUsesFuel”基础对象来继承。

@Michael Rodrigues给出的答案不正确(我道歉;我不能直接评论),这可能会导致一些混乱。

接口实现是一种继承形式…当你实现一个接口时,你不仅继承了所有的常量,你还将你的对象提交为接口指定的类型;这仍然是一种“是”的关系。如果汽车实现了Fillable,那么汽车“是-a”Fillable,并且可以在任何需要使用Fillable的代码中使用。

组合从根本上不同于继承。当您使用组合时,您(如其他回答所示)在两个对象之间建立了“has-a”关系,而不是使用继承时所建立的“is-a”关系。

所以,从其他问题中关于汽车的例子来看,如果我想说一辆汽车“有一个”油箱,我会使用如下的组合:

public class Car {

private GasTank myCarsGasTank;

}

希望这能消除任何误解。

继承带来IS-A关系。复合引出HAS-A关系。 策略模式解释了组合应该用于定义特定行为的算法族的情况。典型的例子是实现飞行行为的鸭子类。

public interface Flyable{
 public void fly();
}

public class Duck {
 Flyable fly;

 public Duck(){
  fly = new BackwardFlying();
 }
}

因此,我们可以有多个实现飞行的类 例如:

public class BackwardFlying implements Flyable{
  public void fly(){
    Systemout.println("Flies backward ");
  }
}
public class FastFlying implements Flyable{
  public void fly(){
    Systemout.println("Flies 100 miles/sec");
  }
}

如果是继承的话,我们就会有两个不同的鸟类,它们会反复实现fly函数。所以继承和组合是完全不同的。

组合和继承是一样的吗?

它们不一样。

组合:它允许以对象的单个实例的方式处理一组对象。组合的目的是将对象“组合”成树状结构,以表示部分-整体层次结构

继承:类从其所有超类继承字段和方法,无论是直接的还是间接的。子类可以覆盖它继承的方法,也可以隐藏它继承的字段或方法。

如果我想实现组合模式,我如何在Java中做到这一点?

维基百科的文章足以在java中实现复合模式。

主要参与者:

组件:

是所有组件的抽象,包括复合组件吗 声明组合中对象的接口

叶:

表示组合中的叶对象 实现所有组件方法

复合材料:

表示一个复合组件(有子组件) 实现操作子节点的方法 实现所有Component方法,通常是将它们委托给其子方法

理解Composite模式的代码示例:

import java.util.List;
import java.util.ArrayList;

interface Part{
    public double getPrice();
    public String getName();
}
class Engine implements Part{
    String name;
    double price;
    public Engine(String name,double price){
        this.name = name;
        this.price = price;
    }
    public double getPrice(){
        return price;
    }
    public String getName(){
        return name;
    }
}
class Trunk implements Part{
    String name;
    double price;
    public Trunk(String name,double price){
        this.name = name;
        this.price = price;
    }
    public double getPrice(){
        return price;
    }
    public String getName(){
        return name;
    }
}
class Body implements Part{
    String name;
    double price;
    public Body(String name,double price){
        this.name = name;
        this.price = price;
    }
    public double getPrice(){
        return price;
    }
    public String getName(){
        return name;
    }
}
class Car implements Part{
    List<Part> parts;
    String name;

    public Car(String name){
        this.name = name;
        parts = new ArrayList<Part>();
    }
    public void addPart(Part part){
        parts.add(part);
    }
    public String getName(){
        return name;
    }
    public String getPartNames(){
        StringBuilder sb = new StringBuilder();
        for ( Part part: parts){
            sb.append(part.getName()).append(" ");
        }
        return sb.toString();
    }
    public double getPrice(){
        double price = 0;
        for ( Part part: parts){
            price += part.getPrice();
        }
        return price;
    }   
}

public class CompositeDemo{
    public static void main(String args[]){
        Part engine = new Engine("DiselEngine",15000);
        Part trunk = new Trunk("Trunk",10000);
        Part body = new Body("Body",12000);

        Car car = new Car("Innova");
        car.addPart(engine);
        car.addPart(trunk);
        car.addPart(body);

        double price = car.getPrice();

        System.out.println("Car name:"+car.getName());
        System.out.println("Car parts:"+car.getPartNames());
        System.out.println("Car price:"+car.getPrice());
    }

}

输出:

Car name:Innova
Car parts:DiselEngine Trunk Body
Car price:37000.0

解释:

Part是一片叶子 汽车包含许多部件 汽车的不同部分已经添加到car中 汽车价格=(各部件价格)之和

关于组合和继承的利弊,请参考下面的问题。

喜欢组合而不是继承?