简体   繁体   中英

Java Interface : Use default method implementation in implementation classes

I have an interface and its 2 or more implementations say,

public interface IProcessor {
  default void method1() {
   //logic
  }
  default void method2() {
   //logic
  }
  public void method3();
  public void method4();
}

Here, The method1 and method2 implementation logic is common across all multiple multiple implementation classes. So defined as default methods. So only the rest of the methods can be overridden in the implementation classes.

public CarImpl implements IProcessor {
  @Override 
  public void method3() {
    //logic
  }
  @Override 
  public void method4() {
    //logic
  }
}

public VanImpl implements IProcessor {
  @Override 
  public void method3() {
    //logic
  }
  @Override 
  public void method4() {
    //logic
  }
}

Is there a better approach that I can achieve this without default methods and without redundant code in the respective implementation classes ? Because if the code in the default methods increases then the interface looks clumsy.

Default methods can be overridden

You said:

So only the rest of the methods can be overridden in the implementation classes.

The word "only" there is incorrect. A default method in an interface can indeed be overridden by an implementing class. Thus the word default used as the keyword here, meaning: use this method code if no other implementing code is present at runtime.

Here is a silly contrived example where we define an interface Fruit with a default method isJuicy that returns true . We have two subclasses, Orange and Banana . The first has no override of isJuicy , so its behavior comes from the default method. The second demonstrates that you can override the default method. Here we see the override return false .

package work.basil.example;

public class OverridingDefault
{
    public static void main ( String[] args )
    {
        OverridingDefault app = new OverridingDefault();
        app.demo();
    }

    private void demo ( )
    {
        System.out.println( "new Orange().isJuicy(): " + new Orange().isJuicy() );
        System.out.println( "new Banana().isJuicy(): " + new Banana().isJuicy() );
    }

    public interface Fruit
    {
        default boolean isJuicy ( )
        {
            return true;
        }
    }

    public class Orange implements Fruit
    {
    }

    public class Banana implements Fruit
    {
        @Override
        public boolean isJuicy ( )
        {
            return false;
        }
    }
}

When run.

new Orange().isJuicy(): true
new Banana().isJuicy(): false

Prefer abstract classes over default methods

You asked:

Is there a better approach that I can achieve this without default methods and without redundant code in the respective implementation classes?

I do suggest you not use default interface methods for this.

The idea and technology for adding default methods to Java interfaces was not as a feature in itself, but as a solution to another problem: Retrofitting functionality onto existing interfaces to support new lambda features but without breaking the existing code of millions of Java programmers as would happen when otherwise adding methods to existing interfaces. By inventing default method on interfaces, the Java team was able to add more methods to existing interfaces while relieving all existing implementations of the need to implement those new methods. New features, without breaking code, a hallmark of Java.

As stated in State of the Lambda by Brian Goetz 2013-09 :

The purpose of default methods (…) is to enable interfaces to be evolved in a compatible manner after their initial publication.

My own opinion is that programmers are generally not going to expect behavior to be built into your interfaces. The classic use of an interface in Java is to define a contract per the method signatures , not define behavior (code). So consider adding adding behavior (code) as default methods only as a last resort.

Instead, define your interface as a contract, with no default methods. At least no default methods at first; you may find later a need as did Brian Goetz and the Java team to add default methods later. But start with only the contract.

Then define an abstract class that implements that interface. Any behavior (code) to be shared across the various subclasses can be moved into this abstract class.

Then go on to define subclasses, concrete classes, that inherit from your abstract class.

With this classic and common approach of interface + abstract class + concrete classes, you have flexibility to make changes, and to make testing easier (with stubs rather than real classes), while efficiently sharing code from one place yet allowing overrides where needed.

You don't do anything wrong, although I'd say abstract classes are better suited in this case, when you have method implementations ( method1 , method2 ) shared across multiple implementations.

If you still want it to be an interface, create a interface and an abstract class extending the interface.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM