Reputation: 2081
My goal is to understand the Interface Segregation Principle and achieve polymorphism at the same time.
My expected result: I can achieve polymorphism with the Interface Segregation Principle.
My actual result: No I can't. I am forced to create boilerplate and use the Liskov Substitution Principle (If there is a Worker, there must be a Worker that can't eat, so create an interface for Worker that can eat that extends Worker). I think I misunderstand the Interface Segregation Principle.
This is the code that violates the Interface Segregation Principle.
public interface IWorker {
void work();
void eat();
}
class Human implements IWorker {
public void work() {
System.out.println("Human is working.");
}
public void eat() {
System.out.println("Human is eating.");
}
}
class Robot implements IWorker {
public void work() {
System.out.println("Robot is working.");
}
public void eat() {
throw new UnsupportedOperationException("Robot cannot eat");
}
}
I was told to separate the interface into 2.
public interface IEatable {
void eat();
}
interface IWorkable {
void work();
}
class Human implements IWorkable, IEatable {
public void work() {
System.out.println("Human is working.");
}
public void eat() {
System.out.println("Human is eating.");
}
}
class Robot implements IWorkable {
public void work() {
System.out.println("Robot is working.");
}
}
The solution is to use the Liskov Substitution Principle.
public interface IWorkable {
void work();
}
interface IEatable {
void eat();
}
interface IWorker extends IWorkable {
}
interface IHumanWorker extends IWorker, IEatable {
}
Upvotes: 2
Views: 286
Reputation: 1911
Your second step looks good, you have split the interface in two more specific interfaces. It does not make sense for a Robot to "eat". (I dont really get the third step)
On the caller side you can now work with your abstractions:
//Polymorphism
List<IWorkable> workers = Arrays.asList(new Robot(), new Human());
//do some work
List<IEatable> eaters = Arrays.asList(new Human(), new Human());
//send for lunch break
If you want to have both behaviours in the same thing, than your abstraction/design seems to be wrong, since Robots cannot eat by definition (indicated by the code smell of not implemented methods).
A Robot is not an IWorker (your first code), because it does not full fill the (full) contract (interface, eat method), no matter how similar it seems to be.
Upvotes: 1
Reputation: 63
I'd recommend using abstract classes for that matter instead of interfaces. If you need every Workable
to work, then you make the method abstract. If it's only optional that they eat, you don't. An example of that would be:
abstract class Workable {
protected String name;
public Workable(String name) {
this.name = name;
}
protected abstract void work();
public void eat() {
System.err.println("\"" + name + "\" can't eat");
}
}
class Human extends Workable {
public Human(String name) {
super(name);
}
@Override
public void work() {
System.out.println("Human " + name + " is working!");
}
@Override
public void eat() {
System.out.println("Human " + name + " is eating!");
}
}
class Robot extends Workable {
public Robot(String name) {
super(name);
}
public void work() {
System.out.println("Robot " + name + " is working!");
}
}
public class Test {
public static void main(String[] args) {
Workable[] workers = new Workable[] {
new Human("Jerry"),
new Robot("XAE12")
};
for (Workable worker : workers) {
worker.work();
worker.eat();
}
}
}
I'm not sure if I understood your question correctly tho, so please let me know if that helped you.
Upvotes: 0