18 · 32 · 5 min
Interface segregation and dependency inversion
The last two, and the second is the most useful idea in the course.
I: interface segregation
No client should be forced to depend on methods it does not use.
interface Worker {
void work();
void eat();
void sleep();
}
class Robot implements Worker {
public void work() { }
public void eat() { throw new UnsupportedOperationException(); }
public void sleep() { throw new UnsupportedOperationException(); }
}Two of those three are lies. Split the interface:
interface Workable { void work(); }
interface Feedable { void eat(); }
class Robot implements Workable { }
class Human implements Workable, Feedable { }D: dependency inversion
Depend on abstractions, not concretions. And the part people miss: both sides depend on the abstraction, including the high-level one.
class OrderService {
private final MySqlDatabase db = new MySqlDatabase(); // welded on
}
class OrderService {
private final Repository repo; // an interface
OrderService(Repository repo) { this.repo = repo; } // handed in
}The second can be tested with an in-memory fake, can switch database without touching order logic, and states its dependency in its constructor where a reader can see it.
Handing a dependency in rather than constructing it is dependency injection, and it is how dependency inversion is achieved in practice.