Reputation: 686
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.
Upvotes: 4
Views: 5005
Reputation: 338604
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
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.
Upvotes: 7
Reputation: 109
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.
Upvotes: 1