Which one to use Implementation inheritance OR Interface inheritance with composition in JAVA?

Prefer interface inheritance to implementation inheritance because it promotes the design concept of coding to an interface and reduces coupling. Interface inheritance can achieve code reuse with the help of object composition. If you look at Gang of Four (GoF) design patterns, you can see that it favors interface inheritance to implementation inheritance.

Implementation inheritance Interface inheritance with composition
Let’s assume that savings account and term deposit account have a similar behavior in terms of depositing and withdrawing money, so we will get the super class to implement this behavior and get the subclasses to reuse this behavior. But saving account and term deposit account have specific behavior in calculating the interest.
Super class Account has reusable code as methods deposit (double amount) and withdraw (double amount).
public abstract class Account {
public void deposit(double amount) {
System.out.println(“depositing ” + amount);
}
public void withdraw(double amount) {
System.out.println(“withdrawing ” + amount);
}
public abstract double calculateInterest(double amount);
}
public class SavingsAccount extends Account {
public double calculateInterest(double amount) {
// calculate interest for SavingsAccount
return amount * 0.03;
}
public void deposit(double amount) {
super.deposit(amount); // get code reuse
// do something else
}
public void withdraw(double amount) {
super.withdraw(amount); // get code reuse
// do something else
}
}
public class TermDepositAccount extends Account {
public double calculateInterest(double amount) {
// calculate interest for SavingsAccount
return amount * 0.05;
}
public void deposit(double amount) {
super.deposit(amount); // get code reuse
// do something else
}
public void withdraw(double amount) {
super.withdraw(amount); // get code reuse
// do something else
}
}
Let’s look at an interface inheritance code sample, which makes use of composition for reusability. In the following example the methods deposit(…) and withdraw(…) share the same piece of code in AccountHelper class. The method calculateInterest(…) has its specific implementation in its own class.
public interface Account {
public abstract double calculateInterest(double amount);
public abstract void deposit(double amount);
public abstract void withdraw(double amount);
}
Code to interface so that the implementation can change.
public interface AccountHelper {
public abstract void deposit(double amount);
public abstract void withdraw(double amount);
}
class AccountHelperImpl has reusable code as methods deposit (double amount) and withdraw (double amount).
public class AccountHelperImpl implements AccountHelper {
public void deposit(double amount) {
System.out.println(“depositing ” + amount);
}
public void withdraw(double amount) {
System.out.println(“withdrawing ” + amount);
}
}
public class SavingsAccountImpl implements Account {
// composed helper class (i.e. composition).
AccountHelper helper = new AccountHelperImpl();
public double calculateInterest(double amount) {
// calculate interest for SavingsAccount
return amount * 0.03;
}
public void deposit(double amount) {
helper.deposit(amount); // code reuse via composition
}
public void withdraw(double amount) {
helper.withdraw(amount); // code reuse via composition
}
}
public class TermDepositAccountImpl implements Account {
// composed helper class (i.e. composition).
AccountHelper helper = new AccountHelperImpl();
public double calculateInterest(double amount) {
//calculate interest for SavingsAccount
return amount * 0.05;
}
public void deposit(double amount) {
helper.deposit(amount); // code reuse via composition
}
public void withdraw(double amount) {
helper.withdraw(amount); // code reuse via composition
}
}

The Test class:

public class Test {
    public static void main(String[] args) {
        Account acc1 = new SavingsAccountImpl();
        acc1.deposit(50.0);
        Account acc2 = new TermDepositAccountImpl();
        acc2.deposit(25.0);
        acc1.withdraw(25);
        acc2.withdraw(10);
        double cal1 = acc1.calculateInterest(100.0);
        double cal2 = acc2.calculateInterest(100.0);
        System.out.println("Savings --> " + cal1);
        System.out.println("TermDeposit --> " + cal2);
    }
}

The output:
depositing 50.0
depositing 25.0
withdrawing 25.0
withdrawing 10.0
Savings –> 3.0
TermDeposit –> 5.0

Tagged . Bookmark the permalink.

Leave a Reply