Design Pattern in Dart: Bridge Pattern

The Bridge Pattern is another structural design pattern — it’s often confused with the Adapter Pattern but serves a different purpose: decoupling abstraction from implementation so they can vary independently.

Here’s your full blog article (in English) about the Bridge Pattern in Dart, with clean examples and explanations for blog readers.


Design Patterns in Dart: Bridge Pattern

What is the Bridge Pattern?

The Bridge Pattern is a structural design pattern used to separate an abstraction from its implementation, allowing both to evolve independently.

In simple terms:

You split your class into two parts:

  • The Abstraction (interface the client sees),
  • The Implementation (the concrete logic behind it).

This is useful when you want to avoid a combinatorial explosion of classes due to multiple dimensions of variation (e.g., shape types + rendering platforms).


When to Use the Bridge Pattern?

  • When you have classes in multiple dimensions that may change independently.
  • When you want to avoid tightly coupling high-level logic to platform-specific details.
  • When supporting multiple rendering engines, OS platforms, or data sources.

Example in Dart: Shapes and Render Engines

Scenario:

You want to draw shapes (Circle, Square) that can be rendered using either Raster or Vector rendering engines.

If you don’t use Bridge, you might end up with:

  • RasterCircle, RasterSquare, VectorCircle, VectorSquare → 4 classes!
    Using Bridge: 2 abstractions × 2 implementations = 4 combinations with just 4 classes, cleanly separated.

Step 1: Define the Implementation Interface

abstract class Renderer {
void renderCircle(double radius);
}

Step 2: Create Concrete Implementations

class RasterRenderer implements Renderer {
@override
void renderCircle(double radius) {
print("Rasterizing a circle with radius $radius");
}
}

class VectorRenderer implements Renderer {
@override
void renderCircle(double radius) {
print("Drawing a circle with radius $radius as vectors");
}
}

Step 3: Define the Abstraction

abstract class Shape {
final Renderer renderer;

Shape(this.renderer);

void draw();
}

Step 4: Create Refined Abstraction (Circle)

class Circle extends Shape {
double radius;

Circle(Renderer renderer, this.radius) : super(renderer);

@override
void draw() {
renderer.renderCircle(radius);
}
}

Step 5: Client Code

void main() {
var raster = RasterRenderer();
var vector = VectorRenderer();

var circle1 = Circle(raster, 5.0);
var circle2 = Circle(vector, 10.0);

circle1.draw(); // Rasterizing a circle with radius 5.0
circle2.draw(); // Drawing a circle with radius 10.0 as vectors
}

Output

Rasterizing a circle with radius 5.0  
Drawing a circle with radius 10.0 as vectors

Adapter vs Bridge — What’s the Difference?

FeatureAdapter PatternBridge Pattern
GoalMake incompatible interfaces compatibleDecouple abstraction and implementation
When to UseIntegrating legacy or 3rd-party codeDesigning for extensibility
DirectionWorks with existing classesDesigned from scratch
Common In FlutterPlugin wrappers, platform bridgesRenderer separation, themes

Benefits of Bridge Pattern

  • Cleanly separates interface from implementation.
  • Supports independent development and testing of each part.
  • Scales well when you have multiple dimensions (e.g., platform × feature).
  • Avoids class explosion in complex hierarchies.

Drawbacks

  • Adds abstraction layers.
  • Slightly more complex design upfront.
  • May feel over-engineered for small-scale apps.

Flutter Use Cases

  • Drawing APIs: Canvas-based shapes rendered using different strategies (e.g., software vs GPU).
  • Multi-platform support: Separate platform logic from UI.
  • Custom themes: Theme abstraction vs implementation per platform or dark/light.

Summary Table

AttributeBridge Pattern
PurposeSeparate abstraction and implementation
Common Use CasesRenderers, Themes, Platform APIs
Easy in Dart?Yes (via abstract classes & composition)
Useful in Flutter?Especially for multi-platform support

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Lên đầu trang