Wzorzec „Dekorator”

Dzięki temu wzorcowi możliwe jest dynamiczne przydzielanie określonemu obiektowi nowych zachowań.

Załóżmy, że interesuje nas utworzenie postaci do gry RPG, którą będziemy mogli wyposażyć w różnego rodzaju ekwipunek, taki jak miecz, zbroja itp. Każdy z tych przedmiotów posiada swoje punkty ataku lub obrony, które podnoszą siłę i wytrzymałość naszej postaci. Przyjmijmy, że utworzymy postać wojownika, który będzie posiadał początkową ilość wspomnianych punktów. Wykorzystując wzorzec „Dekorator” będziemy mogli wzbogacać nasz obiekt poprzez opakowanie go dodatkowymi obiektami.

Na początek utworzymy klasę nadrzędną Character. Zawiera ona metodę służącą do pobierania opisu, który będzie określał co dodaliśmy do naszej postaci. Ponadto, klasa ta zawiera również metody abstrakcyjne do pobierania punktów ataku i obrony.

public abstract class Character {
    String description;

    public String getDescription() {
        return description;
    }

    public abstract int getAttackPoints();
    public abstract int getDefencePoints();
}

Następnie, utworzymy klasę wojownika, w której określone są początkowe punkty postaci.

public class Warrior extends Character {
    private int attackPoints = 5;
    private int defencePoints = 3;

    public Warrior() {
        description = "Wojownik";
    }

    public int getAttackPoints() {
        return attackPoints;
    }

    public int getDefencePoints() {
        return defencePoints;
    }
}

Kolejnym krokiem jest utworzenie klasy abstrakcyjnej Inventory zawierającą metodę do pobierania opisu, przesłaniającą metodę z klasy nadrzędnej.

public abstract class Inventory extends Character {

    public abstract String getDescription();
}

Teraz utworzymy trzy klasy służące jako elementy ekwipunku:
1. Długi miecz

public class LongSword extends Inventory {
    private int attackPoints = 15;
    Character character;

    public LongSword(Character character) {
        this.character = character;
    }

    public String getDescription() {
        return character.getDescription() + ", długi miecz";
    }

    public int getAttackPoints() {
        return character.getAttackPoints() + attackPoints;
    }

    public int getDefencePoints() {
        return character.getDefencePoints();
    }
}

2. Pancerz stalowy

public class SteelArmor extends Inventory {
    private int defencePoints = 15;
    Character character;

    public SteelArmor(Character character) {
        this.character = character;
    }

    public String getDescription() {
        return character.getDescription() + ", pancerz stalowy";
    }

    public int getAttackPoints() {
        return character.getAttackPoints();
    }

    public int getDefencePoints() {
        return character.getDefencePoints() + defencePoints;
    }
}

3. Rękawice stalowe

public class SteelGloves extends Inventory {
    private int defencePoints = 8;
    Character character;

    public SteelGloves(Character character) {
        this.character = character;
    }

    public String getDescription() {
        return character.getDescription() + ", rękawice stalowe";
    }

    public int getAttackPoints() {
        return character.getAttackPoints();
    }

    public int getDefencePoints() {
        return character.getDefencePoints() + defencePoints;
    }
}

Jak widzimy, metody w tych klasach rozszerzają opis oraz zwiększają punkty ataku i obrony naszej postaci. Mając wszystkie klasy możemy napisać kod sprawdzający działanie wzorca „Dekorator”.

public class DecoratorPatternTest {

    public static void main(String[] args) {
        Character begineerWarrior = new Warrior();
        System.out.println(begineerWarrior.getDescription() + '\n'
            + "Punkty ataku: " + begineerWarrior.getAttackPoints() + '\n'
            + "Punkty obrony: " + begineerWarrior.getDefencePoints() + '\n');

        Character intermediateWarrior = new Warrior();
        intermediateWarrior = new LongSword(intermediateWarrior);
        System.out.println(intermediateWarrior.getDescription() + '\n'
                + "Punkty ataku: " + intermediateWarrior.getAttackPoints() + '\n'
                + "Punkty obrony: " + intermediateWarrior.getDefencePoints() + '\n');

        Character advancedWarrior = new Warrior();
        advancedWarrior = new LongSword(advancedWarrior);
        advancedWarrior = new SteelArmor(advancedWarrior);
        advancedWarrior = new SteelGloves(advancedWarrior);
        System.out.println(advancedWarrior.getDescription() + '\n'
                + "Punkty ataku: " + advancedWarrior.getAttackPoints() + '\n'
                + "Punkty obrony: " + advancedWarrior.getDefencePoints() + '\n');
    }
}

Otrzymany tekst z konsoli:

Wojownik
Punkty ataku: 5
Punkty obrony: 3

Wojownik, długi miecz
Punkty ataku: 20
Punkty obrony: 3

Wojownik, długi miecz, pancerz stalowy, rękawice stalowe
Punkty ataku: 20
Punkty obrony: 26

 

Źródła literaturowe:
[1] Eric Freeman, Elisabeth Freeman, Kathy Sierra, Bert Bates – „Wzorce projektowe. Rusz głową!”.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *