Design Pattern in Dart: State Pattern

The State Pattern is another powerful Behavioral Design Pattern that’s particularly relevant in UI-driven apps like Flutter, where an object’s behavior changes based on its internal state.

Here’s your complete English blog post on the State Pattern in Dart, complete with examples and code ready for your readers.


Design Patterns in Dart: State Pattern

What is the State Pattern?

The State Pattern is a behavioral design pattern that allows an object to change its behavior when its internal state changes.
The object will appear to change its class.

In simpler terms:

Instead of using conditionals to track state, you encapsulate state into separate objects and delegate behavior to them.


When to Use the State Pattern?

  • When an object needs to alter its behavior dynamically at runtime.
  • When you find yourself writing a lot of if/else or switch-case based on the current state.
  • When managing UI state transitions, like user authentication, playback controls, or game states.

Example in Dart: Media Player State

Scenario:

You have a media player with 3 states:

  • Stopped
  • Playing
  • Paused

The player’s response to user actions (play, pause, stop) depends on its current state.


Step 1: Define the State Interface

abstract class PlayerState {
void play();
void pause();
void stop();
}

Step 2: Create Concrete States

class StoppedState implements PlayerState {
final MediaPlayer player;

StoppedState(this.player);

@override
void play() {
print("Starting playback...");
player.setState(PlayingState(player));
}

@override
void pause() {
print("Can't pause. Player is stopped.");
}

@override
void stop() {
print("Already stopped.");
}
}

class PlayingState implements PlayerState {
final MediaPlayer player;

PlayingState(this.player);

@override
void play() {
print("Already playing.");
}

@override
void pause() {
print("Pausing playback...");
player.setState(PausedState(player));
}

@override
void stop() {
print("Stopping playback...");
player.setState(StoppedState(player));
}
}

class PausedState implements PlayerState {
final MediaPlayer player;

PausedState(this.player);

@override
void play() {
print("Resuming playback...");
player.setState(PlayingState(player));
}

@override
void pause() {
print("Already paused.");
}

@override
void stop() {
print("Stopping playback from paused state...");
player.setState(StoppedState(player));
}
}

Step 3: Context Class (MediaPlayer)

class MediaPlayer {
late PlayerState _state;

MediaPlayer() {
_state = StoppedState(this);
}

void setState(PlayerState state) {
_state = state;
}

void play() => _state.play();
void pause() => _state.pause();
void stop() => _state.stop();
}

Step 4: Client Code (Switching States at Runtime)

void main() {
var player = MediaPlayer();

player.play(); // Starting playback...
player.pause(); // Pausing playback...
player.play(); // Resuming playback...
player.stop(); // Stopping playback...
player.pause(); // Can't pause. Player is stopped.
}

Output:

Starting playback...
Pausing playback...
Resuming playback...
Stopping playback...
Can't pause. Player is stopped.

Benefits of State Pattern

  • Eliminates large conditional statements (if/else, switch-case).
  • Organizes state-specific behavior into separate classes.
  • Makes it easy to add new states without modifying existing logic.
  • Enhances maintainability and readability.

Drawbacks

  • Can result in a large number of classes.
  • Slightly more verbose than simpler logic for small scenarios.
  • May feel overkill for trivial state logic.

Flutter Use Cases

  • Finite state machines for authentication (logged out, logged in, loading).
  • Player controls (playing, paused, stopped).
  • UI flows: forms, onboarding, error states.
  • Replaces enum + switch-case approach in favor of OOP.

Summary Table

AttributeState Pattern
PurposeChange behavior based on state
Common Use CasesAuth, media player, UI modes
Easy in Dart?Yes, with class-based states
Useful in Flutter?Especially for complex state flows

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