SP4 - Mixer - Learn Design Pattern From Simple Things
You are a dog farm owner who manages the properties of all dog breeds. The number of crossbred dogs is increasing every day because of the emergence of new breeds!
Mixer (Bridge) is a structural design pattern: 🖤🖤🖤🤍🤍
What is Mixer?
Mixer is a structural design pattern that divides business logic or huge class into separate class hierarchies that can be developed independently. One of these hierarchies (often called the Abstraction) will get a reference to an object of the second hierarchy (Implementation).
imagine that you have a class hierarchy of different types of dogs, such as Labrador and Poodle, and another class hierarchy of different types of coats, such as Curly and Straight. You want to be able to create any combination of dog and coat without creating a cartesian product of subclasses, such as LabradorCurly, LabradorStraight, PoodleCurly, and PoodleStraight.
Why use Mixer?
Mixer avoids the problem of creating too many subclasses by separating the two aspects into separate class hierarchies and using composition to combine them. This way, you can reuse the same methods for different types of dogs and coats without creating a cartesian product of subclasses. This makes the code more modular, flexible, and maintainable.
Advantages:
- Reduces code duplication and complexity
- Follows the principle of composition over inheritance
- Allows changing or extending abstractions and implementations independently
- Hides implementation details from the client
Disadvantages:
- Increases the number of classes and objects
- Requires more effort to create the initial abstraction
- May introduce indirection and complexity in some cases
Question: I hate the Mixer, what are the alternatives?
Answer: You can use inheritance instead of composition, but you will have to create more subclasses and repeat the same methods for each combination of dog and coat. This will violate the principle of composition over inheritance and make your code less flexible and maintainable.
When to use Mixer?
Question: When do I need to use Mixer?
Answer: You should use Mixer when you want to avoid creating a large number of subclasses for two orthogonal aspects that can vary independently.
Input:
You have two class hierarchies:
- one for different types of dogs: Labrador, Poodle, …
- another for different types of coats: Curly, Straight, …
class Labrador(Dog):
def bark(self):
print("The labrador barks loudly.")
class Poodle(Dog):
def bark(self):
print("The poodle barks softly.")
class Curly(Coat):
def shed(self):
print("The curly coat sheds little hair.")
class Straight(Coat):
def shed(self):
print("The straight coat sheds moderate hair.")
Expected Output:
- Can use composition to pass an Coat concrete object to Dog concrete object,
- Delegate some of the methods to the Coat object, such as
shed().
The labrador barks loudly.
The straight coat sheds moderate hair.
The poodle barks softly.
The curly coat sheds little hair.
This way, you can reuse the same methods for different types of dogs and coats without creating a cartesian product of subclasses.
How to implement Mixer?
Non-Mixer implementation:
class LabradorCurly:
# A subclass that combines two aspects: labrador and curly
def bark(self):
print("The labrador barks loudly.")
def shed(self):
print("The curly coat sheds little hair.")
class LabradorStraight:
# A subclass that combines two aspects: labrador and straight
def bark(self):
print("The labrador barks loudly.")
def shed(self):
print("The straight coat sheds moderate hair.")
class PoodleCurly:
# A subclass that combines two aspects: poodle and curly
def bark(self):
print("The poodle barks softly.")
def shed(self):
print("The curly coat sheds little hair.")
class PoodleStraight:
# A subclass that combines two aspects: poodle and straight
def bark(self):
print("The poodle barks softly.")
def shed(self):
print("The straight coat sheds moderate hair.")
if __name__ == "__main__":
# Create a labrador with a straight coat
lab_straight = LabradorStraight()
lab_straight.bark()
lab_straight.shed()
# Create a poodle with a curly coat
poo_curly = PoodleCurly()
poo_curly.bark()
poo_curly.shed()
This code has four subclasses that each implement their own methods for barking and shedding. This leads to code duplication and complexity.
If you want to add more types of dogs or coats, you will have to create more subclasses and repeat the same methods. This violates the principle of composition over inheritance.
Mixer Implementation:
class Dog:
# Abstraction
def __init__(self, coat):
# Reference to an object of type Coat
self.coat = coat
def bark(self):
pass
def shed(self):
# Delegate to the Coat object
self.coat.shed()
class Labrador(Dog):
# Refined Abstraction
def bark(self):
print("The labrador barks loudly.")
class Poodle(Dog):
# Refined Abstraction
def bark(self):
print("The poodle barks softly.")
class Coat:
# Implementer
def shed(self):
# Abstract method
pass
class Curly(Coat):
# Concrete Implementation
def shed(self):
print("The curly coat sheds little hair.")
class Straight(Coat):
# Concrete Implementation
def shed(self):
print("The straight coat sheds moderate hair.")
if __name__ == "__main__":
# Create a labrador with a straight coat
lab_straight = Labrador(Straight())
lab_straight.bark()
lab_straight.shed()
# Create a poodle with a curly coat
poo_curly = Poodle(Curly())
poo_curly.bark()
poo_curly.shed()
This follows the principle of composition over inheritance:
-
This code has only two subclasses for each aspect: Labrador and Poodle for dogs, and Curly and Straight for coats.
-
One of these hierarchies (often called the Abstraction) will get a reference to an object of the second hierarchy (Implementation).
This way, you can avoid creating a large number of subclasses for two orthogonal aspects that can vary independently. This makes the code more modular, flexible, and maintainable.
Related posts
-
Verify vs Cert: The Python Requests Handbook
Understanding SSL/TLS in Python Requests: The 'verify' and 'cert' arguments explained with interactive animations.
-
SP7 - Proxy - Learn Design Pattern From Simple Things
The boss wants the employees to focus on work and not get distracted by social media. So he decides to block some websites on the corporate network during working hours.
-
SP6 - Object Pool - Learn Design Pattern From Simple Things
Producing planes on a large scale is expensive, but fortunately the manufactured raw parts are always stored in the pool, thereby reducing duplication in the production process.
-
SP5 - Facade - Learn Design Pattern From Simple Things
There are many departments in the building and you feel confused! By opening the entrances from the facade according to purposes, you simply follow the pre-arranged flow.