关于“优先考虑组成而不是继承”这一主题,我的老师说:

  • 组成:现有类成为新
  • 的组成部分
  • 转发:新类中的每个实例方法,在现有类的所包含实例上调用相应的方法,并返回结果
  • 包装器:新类封装了现有的一个

  • 我对这三个概念不太了解,因此我尝试写下一些代码:
    //Composition is this
    Class A{
        public void doSomething(){
            //do some code
        }
    }
    
    Class B{
        A a = new A();
        public void doOther(){
            a.doSomething();  //this is forwarding
        }
    }
    

    那么包装是什么呢?

    最佳答案

    您的第一个例子不是合成。

    Composition是2个对象之间的“has-a”关系,其中一个对象(组成的对象)是另一个对象(所有者)的字段成员。

    组成为:

    class DemoA {
        DemoB b; //composition
    }
    

    我们会说“DemoA由DemoB组成”。

    如果当DemoB变得不可访问时DemoA对象仍然可用,我们认为DemoBaggregated。例如,尽管密钥环可能已损坏,但仍可以使用密钥。密钥环将由密钥组成,但不拥有密钥,这表示聚合。

    您的转发示例看起来不错,尽管要求确实说“返回结果”,这可能表明方法不应无效:
    class DemoA {
        private DemoB b;
    
        public int doSomething() {
            return b.doSomething(); //forwarding/delegating
        }
    }
    

    至于包装器,它们封装了对象的行为,从而暴露了新的(通常是更复杂的)行为。一个示例就是 DataInputStream ,当InputStream仅能处理原始数据时,它包装String以允许您阅读InputStream对象及更多对象。
    class DemoB {
        public int read() {
            //...Read one int of data
        }
    }
    
    class DemoA {
        private DemoB b;
    
        public DemoA(DemoB b) {
            this.b = b;
        }
    
        public List<Integer> readUntil(List<Integer> dataList, Supplier<Boolean> condition) {
            while(condition.get())
                dataList.add(b.read());
    
            return dataList;
        }
    }
    

    在此示例中,DemoA包装了DemoB以暴露readUntil行为,但DemoB无法做到这一点。

    这是一个愚蠢的示例,但希望表达这一点:我们的DemoB对象无法执行所需的行为(readUntil),因此我们将其包装为可为我们处理该行为的类型,因此我们不会不断重写此类行为。

    10-04 13:04