转发类示例

时间:2013-11-22 18:07:04

标签: java effective-java

阅读Effective Java,我在Item 16: Favor composition over inheritance看到了以下示例。

在下面的InstrumentedSet中,本书显示我们可以跟踪元素的插入次数(通过InstrumentedSet.addCount变量)。

为此,我们只需附加到此类对象的addCount,然后调用ForwardingSet.add(),它会调用实际的Setadd()的实际实现。< / p>

// Reusable forwarding class 
public class ForwardingSet<E> implements Set<E> {     
  private final Set<E> s;     
  public ForwardingSet(Set<E> s) { this.s = s; }     
  public void clear()               { s.clear();            }    
  public boolean contains(Object o) { return s.contains(o); }
...
}

// Wrapper class - uses composition in place of inheritance   
public class InstrumentedSet<E> extends ForwardingSet<E> {     
      private int addCount = 0;     
      public InstrumentedSet(Set<E> s) { super(s); } 
      @Override public boolean add(E e) {         
          addCount++;
          return super.add(e);
       }
       ...
    }

我理解为了使用这种模式/方法,Forwarding*类必须调用其父类的方法的全部(在这种情况下{{1} })?

2 个答案:

答案 0 :(得分:3)

是的,你是对的,ForwardingSet委托/转发所有对支持集的调用。

您可能希望查看热门库Guava中的工作示例:ForwardingMap

答案 1 :(得分:0)

[没有足够的代表发表评论,所以我会留下答案]

回答您的问题:

<块引用>

我的理解是否正确,要使用这种模式/方法,Forwarding* 类必须调用其所有父类的方法(在本例中为 Set)?

是的 - 这是实现装饰器模式的一种方式(如书中所述)。由于 Forwarding* 类实现了一个接口(即 Set<E> 接口),因此它必须遵守接口契约并实现这些方法。

对于您在评论中的问题:

<块引用>

声明一个 ForwardingSet 有什么意义,如果它最终完成 Set 所做的一切? IE。为什么不用 Set 成员变量来声明一个 InstrumentedSet?

这样做可以让您有选择地修改要装饰的方法,从而删除大量样板代码。另外,当界面更新时,你只需要更新一个地方而不是N个地方(如果你有N个装饰器)。代码也更简洁易读,因为我不必在装饰器对象中实现每个方法。

举个例子...

下面我有转发类和 2 个装饰器 - 两者都只在向集合添加内容时修改行为,而没有其他内容..

如果设置界面发生变化,我现在只需要更新一个类 - ForwardingSet 类。如果我没有上那门课并按照你的建议去做,那么我会

  1. 需要在我的每个装饰器中实现整个 Set 接口(可读性不是很好)

  2. 我需要单独更新每个装饰器以实现更改(即新方法)

    public abstract class ForwardingSet<E> implements Set<E> {
          Set<E> delegate;        
    
          // set method delegations ...
    }
    
    
    /**
      * in this decorator I want to log every time something is inserted (and ONLY 
      * inserted)
      */
    public class LoggingSet<E> extends ForwardingSet<E> {       
          // constructor to set delegate
    
          @Override
          public void add(E e) {
            log.info("Adding object to set...")
            super.add(e);
          }
    }
    
    /**
      * in this decorator I increment a counter just like the example - again ONLY when 
      * inserting
      */
    public class CountingSet<E> extends ForwardingSet<E> {       
          int count = 0;
    
          // constructor to set delegate
    
          @Override
          public void add(E e) {
            count++;
            super.add(e);
          }
    }