Strategia (ang. Strategy) jest wzorcem projektowym, który umożliwia elastyczne zarządzanie algorytmami w trakcie działania programu. W tym artykule omówimy, dlaczego wzorzec Strategia jest przydatny, jak działa, oraz przedstawimy przykład jego implementacji.
Dlaczego Strategia?
W projektowaniu oprogramowania często spotykamy się z sytuacjami, w których różne części systemu wymagają różnych algorytmów. W takich przypadkach istotne jest, aby umożliwić elastyczne przełączanie pomiędzy różnymi strategiami bez konieczności modyfikacji istniejącego kodu. Wzorzec Strategia pozwala na odseparowanie algorytmów od reszty programu, co ułatwia zarządzanie nimi i wspiera zasadę otwarte/zamknięte (Open/Closed Principle) z SOLID.
Jak działa Strategia?
Wzorzec Strategia opiera się na definiowaniu rodziny algorytmów, umożliwiając obiektowi wybór jednego z nich w trakcie działania programu. Kluczowym elementem tego wzorca są trzy główne składniki:
- Kontekst (Context): Jest to klasa, która posiada referencję do jednego z obiektów strategii oraz udostępnia interfejs dla klientów do korzystania z wybranego algorytmu.
- Strategia (Strategy): Jest to interfejs lub abstrakcyjna klasa, która definiuje wspólny interfejs dla wszystkich konkret-nych algorytmów.
- Konkretne Strategie (Concrete Strategies): Są to klasy implementujące interfejs strategii, reprezentujące konkretne algorytmy.
Przykład Implementacji
W tym przykładzie, PaymentContext to kontekst, który posiada referencję do interfejsu PaymentStrategy. Klient, korzystając z PaymentContext, może łatwo przełączać pomiędzy różnymi strategiami płatności, co umożliwia elastyczne zarządzanie procesem płatności.
// Interfejs Strategii
interface PaymentStrategy {
void pay(int amount);
}
// Konkretne Strategie
class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("Paying " + amount + " using credit card.");
// Logika płatności kartą kredytową
}
}
class BankTransferPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("Making a bank transfer of " + amount + ".");
// Logika przelewu bankowego
}
}
class CashPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("Paying " + amount + " in cash.");
// Logika płatności gotówką
}
}
// Kontekst
class PaymentContext {
private PaymentStrategy paymentStrategy;
public PaymentContext(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void processPayment(int amount) {
this.paymentStrategy.pay(amount);
}
}
// Klient
public class Client {
public static void main(String[] args) {
// Utworzenie kontekstu płatności z domyślną strategią
PaymentContext paymentContext = new PaymentContext(new CreditCardPayment());
// Realizacja płatności różnymi strategiami
paymentContext.processPayment(100);
// Zmiana strategii płatności
paymentContext.setPaymentStrategy(new BankTransferPayment());
paymentContext.processPayment(200);
paymentContext.setPaymentStrategy(new CashPayment());
paymentContext.processPayment(50);
}
}