Strategy Pattern
Patron de conception comportemental permettant de définir une famille d'algorithmes interchangeables et de les rendre indépendants des clients.
Mis à jour le 11 janvier 2026
Le pattern Strategy est un patron de conception comportemental qui permet de définir une famille d'algorithmes, de les encapsuler individuellement et de les rendre interchangeables. Ce pattern permet à l'algorithme de varier indépendamment des clients qui l'utilisent, favorisant ainsi la composition plutôt que l'héritage. Il constitue une alternative élégante aux structures conditionnelles complexes et facilite l'ajout de nouveaux comportements sans modifier le code existant.
Fondements du Pattern Strategy
- Encapsulation des algorithmes dans des classes séparées implémentant une interface commune
- Découplage entre le contexte d'utilisation et l'implémentation concrète de l'algorithme
- Sélection dynamique de l'algorithme à exécuter en fonction du contexte métier
- Conformité au principe Open/Closed : ouvert à l'extension, fermé à la modification
Avantages du Pattern Strategy
- Élimination des structures conditionnelles complexes (if/switch) en faveur du polymorphisme
- Facilite les tests unitaires en permettant l'isolation et le mock de chaque stratégie
- Améliore la maintenabilité en isolant chaque algorithme dans sa propre classe
- Permet le changement de comportement à l'exécution sans impacter le code client
- Respecte le principe de responsabilité unique en séparant les préoccupations algorithmiques
Exemple Concret : Système de Paiement
// Interface commune pour toutes les stratégies
interface PaymentStrategy {
pay(amount: number): Promise<PaymentResult>;
validate(): boolean;
}
// Stratégie concrète : Carte bancaire
class CreditCardStrategy implements PaymentStrategy {
constructor(
private cardNumber: string,
private cvv: string,
private expiryDate: string
) {}
validate(): boolean {
return this.cardNumber.length === 16 && this.cvv.length === 3;
}
async pay(amount: number): Promise<PaymentResult> {
console.log(`Processing ${amount}€ via Credit Card`);
// Logique de paiement par carte
return { success: true, transactionId: 'CC-' + Date.now() };
}
}
// Stratégie concrète : PayPal
class PayPalStrategy implements PaymentStrategy {
constructor(private email: string) {}
validate(): boolean {
return this.email.includes('@');
}
async pay(amount: number): Promise<PaymentResult> {
console.log(`Processing ${amount}€ via PayPal`);
// Logique de paiement PayPal
return { success: true, transactionId: 'PP-' + Date.now() };
}
}
// Stratégie concrète : Crypto
class CryptoStrategy implements PaymentStrategy {
constructor(private walletAddress: string) {}
validate(): boolean {
return this.walletAddress.startsWith('0x');
}
async pay(amount: number): Promise<PaymentResult> {
console.log(`Processing ${amount}€ via Cryptocurrency`);
// Logique de paiement crypto
return { success: true, transactionId: 'CRYPTO-' + Date.now() };
}
}
// Contexte qui utilise la stratégie
class PaymentProcessor {
private strategy: PaymentStrategy;
setStrategy(strategy: PaymentStrategy): void {
this.strategy = strategy;
}
async processPayment(amount: number): Promise<PaymentResult> {
if (!this.strategy.validate()) {
throw new Error('Invalid payment method configuration');
}
return await this.strategy.pay(amount);
}
}
// Utilisation
const processor = new PaymentProcessor();
// Client A : paiement par carte
processor.setStrategy(new CreditCardStrategy('1234567890123456', '123', '12/25'));
await processor.processPayment(99.99);
// Client B : paiement PayPal
processor.setStrategy(new PayPalStrategy('user@example.com'));
await processor.processPayment(49.50);
// Client C : paiement crypto
processor.setStrategy(new CryptoStrategy('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'));
await processor.processPayment(199.00);Mise en Œuvre du Pattern Strategy
- Identifier les algorithmes ou comportements qui varient et qui sont susceptibles de changer
- Définir une interface commune (Strategy) avec les méthodes que toutes les stratégies doivent implémenter
- Créer des classes concrètes pour chaque variante d'algorithme implémentant l'interface Strategy
- Développer une classe Context qui maintient une référence vers l'objet Strategy et délègue l'exécution
- Permettre au client de choisir et d'injecter la stratégie appropriée dans le contexte
- Tester chaque stratégie de manière isolée pour garantir leur bon fonctionnement
Conseil Pro
Combinez le pattern Strategy avec l'injection de dépendances pour maximiser la flexibilité. Utilisez une factory ou un service locator pour sélectionner la stratégie appropriée en fonction de critères métier (pays, profil utilisateur, montant).
Outils et Frameworks Associés
- TypeScript - Typage fort des interfaces de stratégie pour une meilleure sécurité
- NestJS - Providers et injection de dépendances pour gérer les stratégies
- Redux - Reducers comme stratégies de transformation d'état
- Passport.js - Authentification basée sur des stratégies interchangeables
- Joi/Yup - Validation avec stratégies de schéma configurables
- AWS SDK - Stratégies de retry et de gestion d'erreurs personnalisables
Le pattern Strategy représente un investissement stratégique dans la maintenabilité et l'évolutivité du code. En isolant les algorithmes métier dans des composants interchangeables, les équipes peuvent itérer rapidement sur les fonctionnalités.
