3

I have class implements multiple interfaces which have a same default default method. I am wondering how can I composite the default method from all the interfaces. For example:

interface IA {
    default void doA() {} 
    default void process() { 
        // do something 
    }
}

interface IB { 
    default void doB() {}
    default void process() { 
        // do something 
    }
}

interface IC {
    default void doC() {} 
    default void process() { 
        // do something 
    }
}

// other similar interfaces
....    

class MyClass implements IA, IB, IC, ... {
    public void process() {
       // question: how to avoid iterate all the interfaces? 
       IA.super.process();       
       IB.super.process();
       IC.super.process();
       ...
    }
}

class AnotherClass implements IA, ID, IF, IH, ... {
    public void process() {
        IA.super.process();
        ID.super.process();
        IF.super.process();
        IH.super.process();
        ...
    }
}

In the implementation the method is simply compositing process() from all interfaces. However I have to call IA.super.process(), IB.super.process(), IC.super.process() explicitly. If the interface list is long it's painfully to write all of them. Also I may have different classes to implement different combination of interfaces. Is there other syntax sugar/design pattern/library that allows me to do it automatically?

Update: compare with Composite pattern

Composite pattern is also considerable. But I want to use default method as mixin to give classes different behaviors, while composite pattern doesn't give me static type checking here. Composite pattern also introduces extra memory footprint.

Yiqing Zhu
  • 31
  • 3
  • Is it a requirement to use defaults? Can you change your interfaces? – Michael Mar 29 '17 at 09:55
  • 2
    Are you sure the class shouldn't *delegate* to a List, where IA, IB, etc. would extend Processor? You would then just use a loop. – JB Nizet Mar 29 '17 at 10:06
  • 1
    There is no easy way to let Java do this automatically for you. You could probably do this via reflection (check which interfaces the class implements, then call the `process` method of each one via reflection) but this is going to be complicated and clunky. There are different, better approaches, see what the others are proposing. – Jesper Mar 29 '17 at 10:11
  • 4
    This looks like a slight abuse of what `default` methods are designed for. I suggest you read [this](http://stackoverflow.com/a/28684917/574479) before deciding to go down this path. – biziclop Mar 29 '17 at 10:56

1 Answers1

7

I think your mistake is defining multiple interfaces which are effectively identical (aside from differing default behaviour). It seems wrong in my mind and violates DRY.

I would structure this using the composite pattern:

interface Processable
{
    void process();
}
public interface IA extends Processable //and IB, IC etc.
{
    default void doA()
    {
        // Do some stuff
    }
}


final class A implements IA
{
    void process() { /* whatever */ }
}


class Composite implements IA //, IB, IC etc. 
{
    List<Processable> components = Arrays.asList(
         new A(), new B(), ...
    );

    void process()
    {
         for(Processable p : components) p.process();
    }
}
Michael
  • 41,989
  • 11
  • 82
  • 128
  • I've considered that before. But it doesn't give me static type checking when I want to treat composite as A (let's say, A has a unique behavior `doA()`). Also it increases memory footprint: maintaining a list of components. Default method works like mixin function. It gives classes different behaviors. – Yiqing Zhu Mar 29 '17 at 10:32
  • 4
    @YiqingZhu Default methods are NOT mixins. Using them as mixins anyway (while possible) is fraught with all kinds of problems. Also, thinking about memory footprint at this point is probably not a good idea. First make your code correct and simple. If you've done this and memory footprint becomes an actual, measurable problem, then you can address it. – biziclop Mar 29 '17 at 10:50
  • 2
    I agree with @biziclop. Firstly, the memory footprint is completely negligible. But also, having maintainable code is definitely a higher priority. Anyway, I have edited my answer. I'm not sure I like this as a solution because the structure is getting too complicated. It should work, though. There is a maintainability issue in that you will have to ensure the interfaces `Composite` implements are represented in the list of components. – Michael Mar 29 '17 at 10:51
  • 1
    There are words that make me click that arrow immediately; DRY is one of them. – GhostCat Apr 24 '17 at 16:10