Design Pattern in Dart: Strategy Pattern

The Strategy Pattern is a popular Behavioral Design Pattern, and it fits beautifully with Dart and Flutter, especially in scenarios where you want to swap algorithms or behaviors at runtime.

Here’s a complete blog post in English, ready for your blog — with clear structure, examples, and Dart code.


Design Patterns in Dart: Strategy Pattern

What is the Strategy Pattern?

The Strategy Pattern is a behavioral design pattern that allows you to define a family of algorithms, encapsulate each one, and make them interchangeable at runtime.

In simple terms:

You extract algorithm logic from the class and inject it as a strategy so that you can easily switch between them without modifying the class.


When to Use the Strategy Pattern?

  • When you need to switch algorithms at runtime.
  • When multiple classes share similar logic but with slight variations.
  • When avoiding if-else or switch blocks based on behavior types.

Example in Dart: Payment Strategy

Scenario:

You’re building a shopping app that supports different payment methods: Credit Card, PayPal, and Bitcoin.
Instead of hardcoding the logic, you’ll use Strategy Pattern.


Step 1: Define the Strategy Interface

abstract class PaymentStrategy {
void pay(double amount);
}

Step 2: Implement Concrete Strategies

class CreditCardPayment implements PaymentStrategy {
final String cardNumber;

CreditCardPayment(this.cardNumber);

@override
void pay(double amount) {
print("Paid \$${amount.toStringAsFixed(2)} using Credit Card: $cardNumber");
}
}

class PayPalPayment implements PaymentStrategy {
final String email;

PayPalPayment(this.email);

@override
void pay(double amount) {
print("Paid \$${amount.toStringAsFixed(2)} using PayPal: $email");
}
}

class BitcoinPayment implements PaymentStrategy {
@override
void pay(double amount) {
print("Paid \$${amount.toStringAsFixed(2)} using Bitcoin");
}
}

Step 3: Context Class — the one that uses a strategy

class ShoppingCart {
PaymentStrategy? _paymentStrategy;

void setPaymentStrategy(PaymentStrategy strategy) {
_paymentStrategy = strategy;
}

void checkout(double amount) {
if (_paymentStrategy == null) {
print("Please choose a payment method.");
} else {
_paymentStrategy!.pay(amount);
}
}
}

Step 4: Client Code (Runtime Switching)

void main() {
var cart = ShoppingCart();

// Pay with Credit Card
cart.setPaymentStrategy(CreditCardPayment("1234-5678-9012-3456"));
cart.checkout(99.99);

// Switch to PayPal
cart.setPaymentStrategy(PayPalPayment("user@example.com"));
cart.checkout(49.99);

// Switch to Bitcoin
cart.setPaymentStrategy(BitcoinPayment());
cart.checkout(25.50);
}

Output:

Paid $99.99 using Credit Card: 1234-5678-9012-3456  
Paid $49.99 using PayPal: user@example.com
Paid $25.50 using Bitcoin

Why Use Strategy Over if-else?

Without the Strategy Pattern, your ShoppingCart.checkout() would need a bunch of conditional logic:

if (method == "credit") { ... }
else if (method == "paypal") { ... }
else if (method == "bitcoin") { ... }

This is inflexible, tightly coupled, and violates the Open/Closed Principle.


Benefits of Strategy Pattern

  • Clean separation between algorithm and context.
  • Makes it easy to add new strategies without touching existing code.
  • Promotes code reusability and testability.
  • Eliminates complex conditional logic.

Drawbacks

  • Introduces more classes.
  • Slightly more verbose for simple scenarios.
  • Clients must understand and manage strategies explicitly.

Flutter Use Cases

  • Swapping themes or animations at runtime.
  • Switching data sources (local, remote).
  • Custom validation strategies in forms.
  • Changing widget-building strategies (e.g., list vs grid vs carousel).

🧭 Summary Table

AttributeStrategy Pattern
PurposeEncapsulate and swap behaviors
Common Use CasesPayment, sorting, validation, themes
Easy in Dart?Yes, via abstract classes
Useful in Flutter?Especially for runtime switching

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