首页 > 解决方案 > 如何在复合/装饰模式中减少样板代码

问题描述

在复合/装饰模式中,外部容器会覆盖一些方法来改变行为,但必须将其余方法委托给子组件。

例如:A 类有 10 个方法,B 类包含 A 但只覆盖了 2 个方法,那么 B 必须覆盖 8 个方法只是为了委托给 A 里面的实例。如何在 Java 和 Python 中削减那些样板代码?

编辑:我尽量不让 B 扩展 A 因为我试图比继承更复合。

标签: javapythondesign-patternsdecoratorcomposite

解决方案


我希望你只是要求这样的东西。我将以装饰器模式为例(但您也可以将其应用于其他模式)。

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而不是扩展/实现抽象类/接口。那么你就不需要委托了。该行为将被继承。

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

您可以参考示例,了解如何使用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);
    }
}

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


推荐阅读