如何减少复合/装饰图案中的样板代码

时间:2019-05-13 11:16:37

标签: java python design-patterns decorator composite

在复合/装饰模式中,外部容器会覆盖某些方法来更改行为,但对于其他方法,则必须委托给子组件。

ex:类A有10个方法,类B包含A但仅覆盖2个方法,然后B必须覆盖8个方法才可以委托给A内部的实例。 如何减少Java和Python中的样板代码?

编辑:我尝试不使B扩展为A,因为我尝试比继承更复杂。

3 个答案:

答案 0 :(得分:0)

我希望您只是在问这样的事情。我将以decorator模式为例(但是您也可以将其应用于其他模式)。

class A implements Decorator{    
    @Override
    public void decorate(){
      System.out.print("Decorate A");
    }

    @Override
    public void help(){
      System.out.print("Help");
    }

}

class B implements Decorator{    
    private Decorator member;

    public B(Decorator decorator){
      this.member = decorator;
    }

    @Override
    public void decorate(){
      member.decorate();
      System.out.print("Decorate B");
    }

    @Override 
    public void help(){
      //***you need the behaviour of A here
      member.help();
    }
}

Decorator d = new B(new A());
b.help();

所以在// **行中,如果您想在那里A的行为,只需执行B extends A而不是扩展/实现抽象类/接口。然后,您无需委托。该行为将被继承。

但是,您想在其中执行成员方法的任何方式,使其保持更通用,并使运行时能够决定它,则必须委托。没有其他解决方案,因为该逻辑仅封装在成员类内部,并且在运行时注入实际成员之前,您不知道确切的类型。

您可以参考this示例,以了解如何使用lombok来实现这种装饰器模式委托。

public class RemovalCountingList<E> implements List<E> {
    @Delegate(excludes = ExcludedListMethods.class)
    private final List<E> delegate;
    private final AtomicInteger removalCount = new AtomicInteger();
    public RemovalCountingList(List<E> delegate) {
        this.delegate = delegate;
    }
    @Override
    public E remove(int index) {
        System.out.println("Removal count: " + removalCount.incrementAndGet());
        return delegate.remove(index);
    }
    @Override
    public boolean remove(Object o) {
        boolean isRemoved = delegate.remove(o);
        if (isRemoved) {
            System.out.println("Removal count: " + removalCount.incrementAndGet());
        }
        return isRemoved;
    }
    /**
     * Excluded methods that Lombok will not implement, we will implement/override these methods.
     */
        private abstract class ExcludedListMethods {
            public abstract E remove(int index);
            public abstract boolean remove(Object o);
        }
    }

public class ClientMain {
    public static void main(String[] args) {
        RemovalCountingList<String> cities = new RemovalCountingList<>(new ArrayList<>());
        cities.add("London");
        cities.add("Paris");
        cities.add("Istanbul");
        cities.add("Tokyo");
        String removedCity = cities.remove(0);
        System.out.println("Removed city: " + removedCity);
        boolean isRemoved = cities.remove("Istanbul");
        System.out.println("Is removed?: " + isRemoved);
    }
}

它将帮助您删除样板代码。

答案 1 :(得分:0)

尽管Java语言本身没有可为您节省样板的功能,但您可以看看Lombok的@Delegate注释here,以减少样板(这是Lombok项目所做的事情)。对于您在问题中的示例,可能看起来像这样

interface A {

    void method1();

    void method2();

    // ... 8 more methods
}

public class B implements A {

    private interface AOverride {

        void method1();
    }

    @Delegate(types = A.class, excludes = AOverride.class)
    private final A delegate;

    public B(final A delegate) {
        this.delegate = delegate;
    }

    @Override
    public void method1() {

    }
}

这里唯一令人讨厌的事情是,您将需要定义一个额外的类来指定要覆盖的方法,因为没有将方法名作为字符串的excludes-parameter(可能是一件好事,您希望编译时的安全性。

答案 2 :(得分:0)

Lombok具有实验性的@Delegate功能,您可以尝试:

public class DelegationExample {

  private interface SimpleCollection {
    boolean add(String item);
    boolean remove(Object item);
  }

  @Delegate(types=SimpleCollection.class)
  private final Collection<String> collection = new ArrayList<String>();
}