3

In composite/decorate patter, the outer container overrides some methods to change the behavior, but have to delegate to sub-component for the rest of methods.

ex: class A has 10 methods, class B contains A but only override 2 methods, then B has to override 8 methods just to delegate to the instance of A inside. How to cut those boilerplate codes in Java and Python?

EDIT: I try not to make B extends A cause I try to be more composite than inheritance.

ying
  • 628
  • 1
  • 7
  • 16
  • I know this is not Java, but it's "Java": in Kotlin you can use implementation through delegation. https://kotlinlang.org/docs/reference/delegation.html – AplusKminus May 13 '19 at 11:20
  • Python may allow you to write one generic `__getattr__()` method to automatically delegate, or proxy, many method calls: https://stackoverflow.com/a/26092256 – quamrana May 13 '19 at 12:25

3 Answers3

0

I hope you are simply asking for something like this. I'll take the decorator pattern for example (But you can apply the same to the other also).

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

So in line //**, if you want the behavior of A there, just do B extends A instead of extending/implementing the abstract class/interface. Then you do not need to delegate. That behavior will be inherited.

But any way you want to execute the member method there, keeping it more generic and gives the ability to the runtime to decide it, then you have to delegate. There is no any other solution because that logic is encapsulated only inside the member class and you do not know the exact type until the runtime injects the actual member.

You can refer this example, to see how this decorator pattern delegation can be achieved with 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);
    }
}

It will help you to remove your boilerplate codes.

Supun Wijerathne
  • 11,964
  • 10
  • 61
  • 87
0

While there is no feature from the Java language itself that saves you the boilerplate, you could have a look at Lombok's @Delegateannotation here for less boilerplate (that's what project lombok does). For your example in your question, it could look like this

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() {

    }
}

The only annoying thing here is that you would need to define an extra class to specify which methods you want to override, as there is no excludes-parameter that takes method-names as strings (probably a good thing, you want that compile-time safety).

sfiss
  • 2,119
  • 13
  • 19
0

Lombok has experimental @Delegate feature that you can try:

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>();
}
Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111