Decouples an abstraction from its implementation so both can vary independently.
Avoids a combinatorial explosion of subclasses.
abstract class Color {
String fill();
}
class Red implements Color {
@override
String fill() => 'red';
}
class Blue implements Color {
@override
String fill() => 'blue';
}
abstract class Shape {
final Color color;
Shape(this.color);
String draw();
}
class Circle extends Shape {
Circle(super.color);
@override
String draw() => 'Circle filled with ${color.fill()}';
}
// Usage
print(Circle(Red()).draw()); // Circle filled with red
print(Circle(Blue()).draw()); // Circle filled with blue