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ń.