There are two types of inheritances:
1. Implementation inheritance (aka class inheritance): You can extend an application’s functionality by reusing functionality in the parent class by inheriting all or some of the operations already implemented. In Java, you can only inherit from one superclass. Implementation inheritance promotes reusability but improper use of class inheritance can cause programming nightmares by breaking encapsulation and making future changes a problem. With implementation inheritance, the subclass becomes tightly coupled with the superclass. This will make the design fragile because if you want to change the superclass, you must know all the details of the subclasses to avoid breaking them. So when using implementation inheritance, make sure that the subclasses depend only on the behavior of the superclass, not on the actual implementation.
For example in the above diagram, the subclasses should only be concerned about the behavior known as area() but not how it is implemented.

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
	}
}

2. Interface inheritance (aka type inheritance): This is also known as subtyping. Interfaces provide a mechanism for specifying a relationship between otherwise unrelated classes, typically by specifying a set of common methods each implementing class must contain. Interface inheritance promotes the design concept of program to interfaces not to implementations. This also reduces the coupling or implementation dependencies between systems. In Java, you can implement any number of interfaces. This is more flexible than implementation inheritance because it won’t lock you into specific implementations which make subclasses difficult to maintain. So care should be taken not to break the implementing classes by modifying the interfaces. Let’s look at an interface inheritance code sample, which makes use of composition for reusability.

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 ();
	// here we can use Spring to change implementation dynamically
	//AccountHelper helper = new EfficientAccountHelperImpl();

	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
	}
}

Reference: Joshua Bloch’s book, Effective Java Programming Language Guide, chapter 4, item 14: Favor composition over inheritance.

Another benefit to use composition is to avoid memory retention.
How to Handle Java Finalization’s Memory-Retention Issues

Advertisements