wzorzec strategia:
Wzorzec strategia należy do grupy wzorców behawioralnych, czyli dotyczy algorytmów i rozdzielania odpowiedzialności miedzy różnymi obiektami. Wzorzec ten pozwala zdefiniować całą rodzinę algorytmów, umieścić je w osobnych klasach i spowodować, że obiekty tych klas będą wymienialne. Pozwala to na dynamiczne korzystanie z algorytmu, który jest w danej chwili potrzebny. Natomiast klasa kliencka nie ma pojęcia, który algorytm jest wykorzystywany.
Zastosowanie wzorca:
- gdy chcemy użyć różnych wariantów jednego algorytmu w obrębie obiektu i tym samym dokonywać wyboru wariantu w trakcie działania programu
- gdy mamy wiele podobnych klas które różnią się sposobem wykonywania operacji
- gdy chcemy odizolować logikę biznesową klasy od implementacji algorytmów (bo nie są istotne w kontekście tej logiki)
- gdy chcemy odizolować logikę biznesową klasy od implementacji algorytmów (bo nie są istotne w kontekście tej logiki)gdy klasa zawiera duży operator warunkowy, który decyduje o wyborze wariantu algorytmu
Zatem naszym zadaniem będzie napisać program który poinformuje na jaką imprezę możemy się zdecydować w zależności od budżetu. Dla ułatwienia wyświetlimy tylko informacje na jaką imprezę możemy sobie pozwolić z naszym obecnym budżetem. Do dzieła!
W pierwszej kolejności pokaże kod który nie wykorzystuje wzorca strategia. Oto i on:
public class BirthdayPartyMain {
public static void main(String[] args){
int budget = 1100;
typeOfEvent(budget);
}
public static void typeOfEvent(int budget){
if(budget>0&&budget<300){
System.out.println("Plener!");
}else if(budget>=300&&budget<800){
System.out.println("Niespodzianka!");
}else if(budget>=800){
System.out.println("Bar!");
}else { System.out.println("Nie stać nas na imprezę! Musimy zrobić zrzutkę..."); }
}
}
Jak widać nie jest on dość skomplikowany, ale wyobraź sobie, że mogą dojść nam nowe mozliwosci np. Impreza w wynajętym lokalu itp. Mogą również nastąpić jakieś nowe warunki, które trzeba by było spełnić: czas realizacji, liczba gości, dodatkowe atrakcje itp. Wówczas nasza instrukcja warunkowa mogłaby urosnąć do sporych rozmiarów. Zmiany mogłyby być dla nas sporym utrudnieniem. Nie wspomnę już, że w przykładzie tylko wyświetlamy na ekran typ imprezy na którą możemy sobie pozwolić. A co by było gdyby trzeba wywołać jakieś dodatkowe operacje.
Teraz czas by zająć się tym samym problemem, ale z użyciem ww. wzorca. Zobaczmy jak mógłby wyglądać diagram klas:
Widzimy, że mamy klasę abstrakcyjną Party i rozszerzającą ją klasę Birthday w której zapadnie decyzja której strategii użyjemy w zależności od budżetu. To ona będzie komunikowała się z obiektem strategii za pośrednictwem interfejsu. Jest również wspomniany interfejs dzięki któremu uruchamiamy dana strategię – jest ich cztery. Poniżej umieściłam kod dla poszczególnych klas.
public abstract class Party {
PartyInterface partyInterface;
public double budget;
public void createParty(){
setInterface();
partyInterface.createParty();
}
public void setInterface()
{
this.partyInterface = typeOfEvent();
}
public abstract PartyInterface typeOfEvent();
}
public class Birthday extends Party {
public Birthday(double budget){
this.budget =budget;
}
public PartyInterface typeOfEvent(){
if(budget >0&& budget<300) return new PartyOutdoors();
else if(budget >=300&& budget <800) return new PartySurprise();
else if(budget >=800) return new PartyInClub();
else return new NoParty();
}
}
public interface PartyInterface {
public void createParty();
}
public class NoParty implements PartyInterface {
@Override
public void createParty() {
System.out.println("Nie stać Cię na organizacje imprezy!");
}
}
public class PartyInClub implements PartyInterface {
@Override
public void createParty() {
System.out.println("W klubie");
}
}
public class PartyOutdoors implements PartyInterface {
@Override
public void createParty() {
System.out.println("W plenerze");
}
}
public class PartySurprise implements PartyInterface {
@Override
public void createParty() {
System.out.println("Niespodzianka!");
}
}
Klasa main oraz rezultat wywołania:
import java.awt.image.ImagingOpException;
import java.util.InputMismatchException;
import java.util.Scanner;
public class PartyMain {
public static void main(String[] args) {
//strategy
menu();
boolean flag = true;
while (flag) {
Scanner scan = new Scanner(System.in);
int opcja = scan.nextInt();
switch (opcja) {
case 1: {
System.out.println("Podaj budżet: ");
try {
double budget = scan.nextDouble();
Party birthday = new Birthday(budget);
birthday.createParty();
menu();
} catch (ImagingOpException | InputMismatchException e) {
System.out.println("Podaj liczbę z przecinkiem lub liczbę calkowitą!");
menu();
break;
}break;
}
case 2:
flag = false;
scan.close();
break;
}
}
}
public static void menu() {
System.out.println("MENU");
System.out.println("1. Sprawdz na jaką impreze możesz sobie pozwolić");
System.out.println("2. Wyjdż");
}
}
MENU
1. Sprawdz na jaką impreze możesz sobie pozwolić
2. Wyjdż
1
Podaj budżet:
123,67
W plenerze
Jak widać w zależności od budżetu utworzony obiekt klasy Birthday wybrał odpowiednią strategię. Użycie tego wzorca spowodowało, że jest możliwe dodawanie nowych strategii bez konieczności zmian w klasach.
Podsumowując wzorzec strategia definiuje rodziny algorytmów, dokonuje ich hermetyzacji i powoduje, że stają się one wymienne. Pozwala również na modyfikacje danego algorytmu niezależnie od klienta, który tego algorytmu używa.