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?

asked Jun 10, 2020 at 5:19
2
  • This question is too specific to your situation and yet contains too little information for someone to be able to provide a useful answer to you. It also asks for a best answer which will only result in people providing their opinions, something that this site tries to avoid. You need to clearly state your assumptions and ask specific questions about what you are trying to achieve. Commented Jun 10, 2020 at 16:57
  • What about making the interface an abstract class? Commented Jun 17, 2020 at 13:39

3 Answers 3

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.

answered Jun 10, 2020 at 6:42
12
  • 1
    I typically prefer having the no-arg constructor do this(new UtilityDefault()); but yes, this seems to be the right answer for this situation. Java interfaces have support for default methods but there's no way to make them private. Commented Jun 10, 2020 at 20:32
  • @JimmyJames I find myself curious about that practice. Care to cite any arguments for it? Commented Jun 10, 2020 at 20:44
  • @candied_orange I don't have a reference but my reasoning is that it means there is only on place in the class where that variable is assigned. (Side note: I also almost always make my member variables final.) Along similar lines, I've moved more towards using factory methods and having only one private constructor on a class à la Josh Bloch's "Effective Java". Commented Jun 11, 2020 at 14:40
  • @JimmyJames true, but it makes one constructor dependant on another. It also means where is more than one place in the class where the order of the constructor parameters is defined. Not sure how to weigh that against duplicate assignments. However, with final you clearly have a good point. You caught me being lazy. Will edit. Commented Jun 11, 2020 at 14:49
  • @JimmyJames Now if I was doing validation in the constructor you'd have an overwhelming point since who wants to duplicate that? I suppose making it easy to do that later would be a good reason to do this() now Commented Jun 11, 2020 at 14:54
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.

answered Jun 10, 2020 at 5:42
0
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.

answered Jun 10, 2020 at 5:40
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.