
Transform your rigid inheritance into flexible delegations
TL;DR: Replace restrictive inheritance hierarchies with flexible object delegation
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-iii-t7h3zkv
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xiv
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-vii-8dk31x0
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxv
class Chatbot {
public void respond(String question) {
// Here is the logic to answer a question
}
}
class Robot extends Chatbot {
// The Physical Robot inherits the logic
// to answer questions
// and adds physical behavior
public void move() {
System.out.println("Moving...");
}
public void grab() {
System.out.println("Grabbing object...");
}
}
class Brain {
public String answer(String question) {
// The common logic to answer questions
// is extracted into a different object
return "Thinking... Answering: " + question;
}
}
final class Chatbot {
private final Brain brain;
Chatbot(Brain brain) {
this.brain = brain;
}
public void respond(String question) {
System.out.println(this.brain.answer(question));
}
}
final class Robot {
// 4. Remove inheritance and update object creation.
private final Brain brain;
// 1. Create a temporary field in the subclass for the superclass.
// private final Chatbot chatbot;
Robot(Brain brain) {
this.brain = brain;
// 2. Update subclass methods to delegate calls.
// this.chatbot = new Chatbot(brain);
// This code is removed after step 4
}
public void move() {
System.out.println("Moving...");
}
public void grab() {
System.out.println("Grabbing object...");
}
public void respond(String question) {
// 3. Add delegation methods for inherited behavior.
// chatbot.respond(question);
// This code is also removed after step 4
System.out.println(this.brain.answer(question));
// The physical robot can also use it as text-to-speech
}
}
This refactoring is safe when done carefully and with proper testing.
You should ensure all delegated method signatures match exactly and maintain existing behavior.
The main risk comes from missing methods that need delegation or incorrectly implementing the delegation methods.
You gain the flexibility to change implementations at runtime and avoid the pitfalls of inheritance like tight coupling.
This refactoring improves the Bijection between code and reality by better modeling real-world relationships.
A robot doesn't inherit from a brain in the real world - it has a brain.
By replacing inheritance with delegation, you create a more accurate representation of the actual relationship between objects using the MAPPER.
The rewriting requires writing additional delegation methods.
If subclass logic relies too much on the superclass, delegation might increase boilerplate.
Without Proper Instructions |
With Specific Instructions |
---|---|
Image by Gerd Altmann on Pixabay
This article is part of the Refactoring Series.