作文,我不太明白吗?

Jon*_*Jon 3 oop composition

参考以下链接:

http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html?page=2

代码重用的组合方法提供了比继承更强的封装,因为对后端类的更改不需要破坏任何仅依赖于前端类的代码.例如, 更改前一个示例中Fruit的peel()方法的返回类型不会强制更改Apple的界面,因此无需破坏Example2的代码.

当然如果你改变返回类型peel()(见下面的代码),这意味着getPeelCount()将无法再返回int?你不是必须改变界面,否则会得到编译器错误?

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Yan*_*hon 6

使用合成,更改类Fruit不需要您更改Apple,例如,让我们改变peel以返回a double:

class Fruit {

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

        System.out.println("Peeling is appealing.");
        return 1.0;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,类Apple会警告精度会丢失,但是你的Example2类会很好,因为组合更"松散",组合元素的更改不会破坏组合类API.在我们的案例中,只需改变Apple如下:

class Apple {

    private Fruit fruit = new Fruit();

    public int peel() {
        return (int) fruit.peel();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果从()Apple 继承,您不仅会收到有关不兼容的返回类型方法的错误,而且还会收到编译错误.Fruitclass Apple extends FruitExample2

**编辑**

让我们从头开始,给出一个"真实世界"的组合继承的例子.请注意,合成不仅限于此示例,还有更多用例可以使用该模式.

例1:继承

应用程序将形状绘制到画布中.应用程序不需要知道它必须绘制哪些形状,实现位于继承抽象类或接口的具体类中.但是,应用程序知道它可以创建多少不同的混凝土形状,因此添加或删除混凝土形状需要在应用程序中进行一些重构.

interface Shape {
   public void draw(Graphics g);
}

class Box implement Shape {
   ...
   public void draw(Graphics g) { ... }
}

class Ellipse implements Shape {
   ...
   public void draw(Graphics g) { ... }
}

class ShapeCanvas extends JPanel {
   private List<Shape> shapes;
   ...
   protected void paintComponent(Graphics g) {
      for (Shape s : shapes) { s.draw(g); }
   }
}
Run Code Online (Sandbox Code Playgroud)

实施例2:组合物

应用程序正在使用本机库来处理某些数据.实际的库实现可能已知,也可能未知,并且将来可能会或可能不会发生变化.这样就创建了一个公共接口,并在运行时确定了实际的实现.例如 :

interface DataProcessorAdapter {
   ...
   public Result process(Data data);
}

 class DataProcessor {
    private DataProcessorAdapter adapter;
    public DataProcessor() {
       try {
          adapter = DataProcessorManager.createAdapter();
       } catch (Exception e) {
          throw new RuntimeException("Could not load processor adapter");
       }
    }
    public Object process(Object data) {
       return adapter.process(data);
    }
 }

 static class DataProcessorManager {
    static public DataProcessorAdapter createAdapter() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        String adapterClassName = /* load class name from resource bundle */;

        Class<?> adapterClass = Class.forName(adapterClassName);
        DataProcessorAdapter adapter = (DataProcessorAdapter) adapterClass.newInstance();
        //...

        return adapter;
    }
 }
Run Code Online (Sandbox Code Playgroud)

因此,正如您所看到的,组合可能提供一些优于继承的优势,因为它允许代码具有更大的灵活性.它允许应用程序具有可靠的API,而底层实现在其生命周期中可能仍会发生变化.如果使用得当,组合物可以显着降低维护成本.

例如,在使用JUnit for Exemple 2实现测试用例时,您可能希望使用虚拟处理器并设置DataProcessorManager返回此类适配器,同时在生产中使用"真实"适配器(可能依赖于OS)而不更改应用程序源代码.使用继承,你很可能会破解一些东西,或者可能会编写更多的初始化测试代码.

正如你所看到的,compisitioninheritance在很多方面都有所不同,并不比另一方面更受欢迎 ; 每个都取决于手头的问题.你甚至可以混合继承和组合,例如:

static interface IShape {
   public void draw(Graphics g);
}

static class Shape implements IShape {
   private IShape shape;
   public Shape(Class<? extends IShape> shape) throws InstantiationException, IllegalAccessException { 
      this.shape = (IShape) shape.newInstance(); 
   }
   public void draw(Graphics g) {
      System.out.print("Drawing shape : ");
      shape.draw(g); 
   }
}

static class Box implements IShape {
   @Override
   public void draw(Graphics g) {
      System.out.println("Box");
   }
}

static class Ellipse implements IShape {
   @Override
   public void draw(Graphics g) {
      System.out.println("Ellipse");
   }        
}

static public void main(String...args) throws InstantiationException, IllegalAccessException {
   IShape box = new Shape(Box.class);
   IShape ellipse = new Shape(Ellipse.class);

   box.draw(null);
   ellipse.draw(null);
}
Run Code Online (Sandbox Code Playgroud)

当然,这最后一个例子是不干净(意味着,避免它),但它示出了组合物如何可以被使用.

底线是两个示例,DataProcessor并且Shape是"可靠"类,并且它们的API不应该更改.但是,适配器类可能会更改,如果它们这样做,这些更改应该只影响它们的组合容器,从而将维护限制为仅限于这些类而不是整个应用程序,而不是示例1,其中任何更改都需要在整个应用程序中进行更多更改.这一切都取决于您的应用程序需要多么灵活.