Strategia jest to zestaw działań w celu osiągnięcia danego celu. Mówimy że opracowujemy strategie działań co w zasadzie jest planem działań.
W programowaniu wzorzec strategia pomaga w osiągnięciu danych celów poprzez dzielenie danego zagadnienia na mniejsze oraz mniej skomplikowane co z kolei pomaga je rozwiązać. Rozważmy to na przykładzie poniżej. Zadeklarowaliśmy dwa interfejsy.
Strzelanie
public interface Strzelanie {
public void strzal();
}
oraz WalkaBroniaBiala
public interface WalkaBroniaBiala {
public void cios();
}
Jak można zaobserwować dotyczą one używania danych rodzajów broni.Interfejs Strzelanie implementują dwie klasy:
StrzalZPistoletu
public class StrzalZPistoletu implements Strzelanie{
@Override
public void strzal() {
System.out.println("Strzal z pistoletu");
}
}
StrzalZKarabinu
public class StrzalZKarabinu implements Strzelanie{
@Override
public void strzal() {
System.out.println("Strzał z karabinu");
}
}
W analogiczny sposób tworzymy klasy Noz oraz Katana
public class Noz implements WalkaBroniaBiala{
@Override
public void cios() {
System.out.println("cios nożem");
}
}
public class Katana implements WalkaBroniaBiala{
@Override
public void cios() {
System.out.println("Cios kataną");
}
}
Umożliwia ona symulacje działań dwóch rodzajów broni. Jednak nadal zadajemy sobie pytanie: Jak ich używać? Otóż najlepszym rozwiązaniem jest wykonanie odpowiedniej klasy sterującej która będzie właścicielem tychże klas. W moim krótkim projekcie będzie to klasa abstrakcyjna Gangster
public abstract class Gangster {
Strzelanie strzelanie;
WalkaBroniaBiala walkaBroniaBiala;
public void bieganie(){
System.out.println("bieg");
}
public void plywanie(){
System.out.println("plywanie");
}
public void ustawStrzelanie(Strzelanie strzelanie){
this.strzelanie=strzelanie;
}
public void ustawWalkaBroniaBiala(WalkaBroniaBiala walkaBroniaBiala){
this.walkaBroniaBiala=walkaBroniaBiala;
}
public void strzal(){
strzelanie.strzal();
}
public void walkaBroniaBiala(){
walkaBroniaBiala.cios();
}
}
Jednak jak dobrze wiemy klasa abstrakcyjna nie może posiadać obiektów w związku z tym niezbędne jest utworzenie klas dziedziczących po niej. W moim projekcie są to klasy MichaelCorleone oraz VitoCorleone
public class MichaelCorleone extends Gangster{
public MichaelCorleone(){
strzelanie= new StrzalZPistoletu();
walkaBroniaBiala= new Noz();
}
}
public class VitoCorleone extends Gangster{
public VitoCorleone(){
strzelanie=new StrzalZKarabinu();
walkaBroniaBiala= new Katana();
}
}
Klasy te posiadają jedynie swój konstruktor który tworzy obiekty danych klas i przypisuje je do zmiennych odziedziczinych po klasie gangster. Na końcu przetestujmy działanie programu
public class TestGangster {
public static void main(String[] args){
Gangster Michael= new MichaelCorleone();
System.out.println("Michael Corleone");
Michael.strzal();
Michael.ustawStrzelanie(new StrzalZKarabinu());
Michael.strzal();
Michael.walkaBroniaBiala();
Gangster Vito= new VitoCorleone();
System.out.println("Vito Corleone");
Vito.strzal();
Vito.ustawStrzelanie(new StrzalZPistoletu());
Vito.strzal();
Vito.walkaBroniaBiala();
}
}
Na początku tworzymy zmienne klas MichaelCorleone oraz VitoCorleone. Pozwala to na wykonanie strzałów. Możliwa jest także zmiana broni porzez metodę ustawStrzelanie. Wynik działania jest następujący.
Michael Corleone
Strzal z pistoletu
Strzał z karabinu
cios nożem
Vito Corleone
Strzał z karabinu
Strzal z pistoletu
Cios kataną
Jak można zaobserwować strategia zastosowania w projekcie odniosła skutek. Obiekty przypisane do klasy Gangster de facto należą do niej a ich użytkownicy mogą decydować czy wybierają tą bądź inną implementacje danego interfejsu, podobnie jak Gangster może wybrać tą lub inną broń.