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, …
|
|
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()
.
|
|
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:
|
|
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:
|
|
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.