Strategy (Stratégia)
Kategória: Viselkedési minta (Behavioral Pattern)
Lényege és célja
A Strategy minta lehetővé teszi, hogy algoritmusok (vagy üzleti logikák) egy családját hozzuk létre, azokat külön osztályokba zárjuk (kapszulázzuk), és futásidőben dinamikusan cserélhetővé tegyük őket.
A minta lényege a "Mit csinálok?" és a "Hogyan csinálom?" szétválasztása. A kliens (Context) tudja, hogy fizetni akar, de azt, hogy ez a fizetés hogyan történik (bankkártya, PayPal, utalás), a betöltött stratégia dönti el.
Miért jobb ez, mint a sok if-else?
Képzelj el egy fizetési rendszert minta nélkül:
if (paymentMethod.equals("CREDIT_CARD")) {
// 50 sor kártyás logika
} else if (paymentMethod.equals("PAYPAL")) {
// 50 sor paypal logika kuponokkal
}
Mikor használjuk?
- Amikor egy objektumon belül egy algoritmusnak több különböző változata (variációja) van, és ezek között futásidőben kell váltani (pl. fizetési módok, útvonaltervezés [séta/autó/bicikli], adat-tömörítés [ZIP/RAR]).
- Amikor el akarunk tüntetni egy hatalmas, komplex
if-elsevagyswitchblokkot, ami algoritmusok között választ. - Amikor az algoritmus (pl. a PayPal kuponozás) saját belső állapottal és függőségekkel rendelkezik, amit el akarunk rejteni a fő üzleti logika (a Kosár) elől.
Mermaid Diagram
A diagramon látható a Context (ShoppingCart) és a Strategy (PaymentStrategy) kapcsolata. A kliens kiválasztja a megfelelő konkrét stratégiát, odaadja a kosárnak, a kosár pedig egyszerűen meghívja a pay() metódust.
classDiagram
class ShoppingCart {
-paymentStrategy: PaymentStrategy
+ShoppingCart(strategy: PaymentStrategy)
+setPaymentStrategy(strategy: PaymentStrategy) void
+checkout(amount: int) void
}
class PaymentStrategy {
<<interface>>
+pay(amount: int) void
}
class CreditCardPayment {
+pay(amount: int) void
}
class PayPalPayment {
-paypalCouponCode: String
+PayPalPayment(code: String)
+pay(amount: int) void
}
class Client
Client --> ShoppingCart : "használja"
%% A ShoppingCart kompozícióval tartalmazza a stratégiát
ShoppingCart o--> PaymentStrategy : "delegálja a feladatot (HAS-A)"
CreditCardPayment ..|> PaymentStrategy : "implementálja"
PayPalPayment ..|> PaymentStrategy : "implementálja"
Client --> CreditCardPayment : "példányosítja"
Client --> PayPalPayment : "példányosítja"
note for ShoppingCart "checkout(amount) {\n paymentStrategy.pay(amount);\n}" Forráskód
package behavioral.strategy;
interface PaymentStrategy {
void pay(int amount);
}
class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.printf("Fizetve %s Ft bankkártyával.\n", amount);
}
}
class PayPalPayment implements PaymentStrategy {
private final String paypalCouponCode;
public PayPalPayment(String paypalCouponCode) {
this.paypalCouponCode = paypalCouponCode;
}
@Override
public void pay(int amount) {
System.out.printf("Fizetve %s Ft paypallal.\n", paypalCouponCode.equals("gemini") ? amount / 2 : amount);
}
}
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public ShoppingCart(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
void checkout(int amount) {
paymentStrategy.pay(amount);
}
}
class Main {
static void main() {
var shoppingCart = new ShoppingCart(new CreditCardPayment());
shoppingCart.checkout(3000);
shoppingCart.setPaymentStrategy(new PayPalPayment("gemini"));
shoppingCart.checkout(3000);
}
}