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-elseorswitchblocks 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
| Attribute | Strategy Pattern |
|---|---|
| Purpose | Encapsulate and swap behaviors |
| Common Use Cases | Payment, sorting, validation, themes |
| Easy in Dart? | Yes, via abstract classes |
| Useful in Flutter? | Especially for runtime switching |



