Design Pattern in Dart: Adapter

What is the Adapter Pattern?

The Adapter Pattern is a structural design pattern that allows objects with incompatible interfaces to work together. It acts like a bridge between two different interfaces.

In simple terms:

“Convert the interface of a class into another interface that clients expect.”


When to Use the Adapter Pattern?

  • When you want to use an existing class but its interface doesn’t match your needs.
  • When integrating legacy code or third-party libraries into your codebase.
  • When building cross-platform bridges in Flutter (e.g., iOS/Android native APIs).

Real-World Example in Dart: Audio Player Adapter

Scenario:

You have a legacy audio player class with a method playFile(String path),
but your app expects a MediaPlayer interface with play(String filename).


Step 1: Target Interface (What your app expects)

abstract class MediaPlayer {
void play(String filename);
}

Step 2: Existing Incompatible Class (Legacy or 3rd-party)

class LegacyAudioPlayer {
void playFile(String path) {
print("Playing audio file: $path using LegacyAudioPlayer");
}
}

Step 3: Create the Adapter

class AudioPlayerAdapter implements MediaPlayer {
final LegacyAudioPlayer legacyPlayer;

AudioPlayerAdapter(this.legacyPlayer);

@override
void play(String filename) {
// Adapt the method call
legacyPlayer.playFile(filename);
}
}

Step 4: Use It in Client Code

void main() {
// Original incompatible class
LegacyAudioPlayer legacy = LegacyAudioPlayer();

// Adapter wraps the legacy class
MediaPlayer player = AudioPlayerAdapter(legacy);

// Client code uses the expected interface
player.play("song.mp3");
}

Output:

Playing audio file: song.mp3 using LegacyAudioPlayer

Explanation

  • The Adapter (AudioPlayerAdapter) implements the expected interface (MediaPlayer).
  • It internally uses the incompatible class (LegacyAudioPlayer) and translates the call.
  • The client stays decoupled from the implementation and works with a unified interface.

Benefits of Adapter Pattern

  • Enables code reuse by adapting incompatible classes.
  • Promotes loose coupling between client and service implementations.
  • Helps with migration from legacy systems.
  • Makes it easy to mock or replace dependencies for testing.

Drawbacks

  • Adds extra layers of abstraction.
  • Can become messy if overused or combined with multiple adapters.
  • May hide complex transformations that reduce performance clarity.

Flutter Use Cases

  • Creating platform bridges with MethodChannel (Android/iOS → Dart).
  • Wrapping native plugins in Flutter with a unified interface.
  • Adapting APIs from different backend services to your app’s models.

Summary Table

AttributeAdapter Pattern
PurposeBridge incompatible interfaces
Common Use CasesAPI wrapping, legacy integration
Easy in Dart?Yes, via abstract classes + composition
Useful in Flutter?Especially with plugins/platforms

Để 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