作文,我不太明白吗? [英] Composition, I don't quite get this?

查看:54
本文介绍了作文,我不太明白吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请参阅以下链接:

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

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

The composition approach to code reuse provides stronger encapsulation than inheritance, because a change to a back-end class needn't break any code that relies only on the front-end class. For example, changing the return type of Fruit's peel() method from the previous example doesn't force a change in Apple's interface and therefore needn't break Example2's code.

当然,如果您更改了peel()的返回类型(请参见下面的代码),这意味着getPeelCount()将不再能够返回int吗?您是否不必更改接口,否则会出现编译器错误?

Surely if you change the return type of peel() (see code below) this means getPeelCount() wouldn't be able to return an int any more? Wouldn't you have to change the interface, or get a compiler error otherwise?

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

推荐答案

使用组成,无需更改类Fruit就需要您更改Apple,例如,让我们更改peel以返回double代替:

With a composition, changing the class Fruit doesn't necessary require you to change Apple, for example, let's change peel to return a double instead :

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

现在,类Apple将警告精度降低,但您的Example2类将很好,因为合成的内容更加宽松",并且对composed元素的更改不会破坏composition的类API.在我们的示例中,只需像这样更改Apple:

Now, the class Apple will warn about a lost of precision, but your Example2 class will be just fine, because a composition is more "loose" and a change in a composed element does not break the composing class API. In our case example, just change Apple like so :

class Apple {

    private Fruit fruit = new Fruit();

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

如果从Fruit(class Apple extends Fruit)继承了Apple ,则不仅会收到有关不兼容的返回类型方法的错误,还会在中出现编译错误Example2.

Whereas if Apple inherited from Fruit (class Apple extends Fruit), you would not only get an error about an incompatible return type method, but you'd also get a compilation error in Example2.

** 编辑 **

让我们从头开始,并举例说明组成继承.请注意,组成不限于此示例,并且有更多的用例可以使用该模式.

Lets start this over and give a "real world" example of composition vs inheritance. Note that a composition is not limited to this example and there are more use case where you can use the pattern.

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

An application draw shapes into a canvas. The application does not need to know which shapes it has to draw and the implementation lies in the concrete class inheriting the abstract class or interface. However, the application knows what and how many different concrete shapes it can create, thus adding or removing concrete shapes requires some refactoring in the application.

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

示例2:组成

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

Example 2 : Composition

An application is using a native library to process some data. The actual library implementation may or may not be known, and may or may not change in the future. A public interface is thus created and the actual implementation is determined at run-time. For example :

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

因此,如您所见,在允许代码更具灵活性的意义上,组合可能比继承具有一些优势.它允许应用程序具有可靠的API,而底层实现在生命周期中仍可能会发生变化.正确使用组合物可以大大降低维护成本.

So, as you can see, the composition may offer some advantage over inheritance in the sense that it allows more flexibility in the code. It allows the application to have a solid API while the underlaying implementation may still change during it's life cycle. Composition can significantly reduce the cost of maintenance if properly used.

例如,当使用JUnit为示例2 实施测试用例时,您可能想要使用虚拟处理器并设置DataProcessorManager以返回此类适配器,同时使用真实"适配器(可能取决于OS)在生产环境中运行,而无需更改应用程序源代码.使用继承,您很可能会破解某些东西,或者编写更多的初始化测试代码.

For example, when implementing test cases with JUnit for Exemple 2, you may want to use a dummy processor and would setup the DataProcessorManager to return such adapter, while using a "real" adapter (perhaps OS dependent) in production without changing the application source code. Using inheritance, you would most likely hack something up, or perhaps write a lot more initialization test code.

如您所见,组成继承力在许多方面有所不同,因此它们并不比其他方面更受青睐;每个都取决于眼前的问题.您甚至可以混合继承和组合,例如:

As you can see, compisition and inheritance differ in many aspects and are not preferred over another; each depend on the problem at hand. You could even mix inheritance and composition, for example :

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

当然,最后一个例子不是干净的(意思是,避免使用),但是它显示了组合 的使用方式.

Granted, this last example is not clean (meaning, avoid it), but it shows how composition can be used.

最重要的是,两个示例DataProcessorShape都是实体"类,它们的API不应更改.但是,适配器类可能会更改,并且如果发生更改,则这些更改仅会影响其组成容器,因此将维护仅限于这些类,而不是整个应用程序,与示例1 相反需要在整个应用程序中进行更多更改.这完全取决于您的应用程序需要具有多大的灵活性.

Bottom line is that both examples, DataProcessor and Shape are "solid" classes, and their API should not change. However, the adapter classes may change and if they do, these changes should only affect their composing container, thus limit the maintenance to only these classes and not the entire application, as opposed to Example 1 where any change require more changes throughout the application. It all depends how flexible your application needs to be.

这篇关于作文,我不太明白吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆