3

Java interface design: where should I put a lot of duplicate code that will be used by all subclasses?

interface Tuple {
    void method1();
}
class Tuple1 implements Tuple {
    @Override
    public void method1() {
        utilityMethod();
        // some code ....
    }
    private void utilityMethod(){ 
        // some code....
    }
}
class Tuple2 implements Tuple {
    @Override
    public void method1() {
        utilityMethod();
        // some code ....
    }
    private void utilityMethod(){
        // some code....
    }
}

Interface can't define final or private method, the utilityMethod is private and it shouldn't be overrided. The utilityMethod will be used by all subclasses of Tuple, where should I put the utilityMethod best?

Guo
  • 177

3 Answers3

7

Java interface design: where should I put a lot of duplicate code that will be used by all subclasses?

First, this is not interface design. This is implementation detail. Nothing outside Tuple needs to know where you put your code.

Second, be sure this duplicate code really should be lumped together. Sometimes code needs to be allowed to change independently.

Finally, consider a solution that is extensible but follows convention over configuration:

interface Tuple {
    void method1();
}
class Tuple1 implements Tuple {
    private final Utility utility;
    Tuple1() { this( new UtilityDefault() ); }
    Tuple1(Utility utility) { this.utility = utility; }

    @Override
    public void method1() {
        utility.method();
        // some code ....
    }
}
class Tuple2 implements Tuple {
    private final Utility utility;
    Tuple1() { this( new UtilityDefault() ); }
    Tuple1(Utility utility) { this.utility = utility; }

    @Override
    public void method1() {
        utility.method();
        // some code ....
    }
}

This way UtilityDefault provides the conventional utility method. But you're allowed to replace that when constructing a Tuple if there is a need. Done this way construction code remains simple for the typical cases.

candied_orange
  • 119,268
6

It depends, but the usual alternatives are

  • make it a static member of a separate utility class

  • make it a member of a separate class (you will have to instantiate an object of that class somewhere)

  • put it into a common base class TupleBase which derives from Tuple, and let Tuple1, Tuple2 derive from TupleBase.

And without providing more context and meaningless names like Tuple1 or utilityMethod don't expect to get a more specific answer.

Doc Brown
  • 218,378
4

Have a look a Java abstract classes and see if that works for your current use case. An AbstractTuple or BaseTuple or GenericTuple can "fill-in" the methods you wish to have shared between implementations and leave abstract methods to be defined by concrete classes. This should generate a compiler warning and should be pretty safe to use.

When designing an application architecture, beware of side effects as more and more concrete classes depend on certain behaviour. Having variables track state and object factories with feature flags can help to address this issue in the future.

As an alternative to consider, have a TupleHelper or TupleUtils static class that takes a ITuple and performs various operations on the tuple. This helps separate behaviour into composable methods that can be chained together to achieve a goal.

fuhoi
  • 51