Korrektur eines großen Nachteils am Dekorationsmuster

Ich habe mich vor einiger Zeit entschlossen, bei der Überarbeitung eines Kampfcodes das Dekorationsmuster auszuprobieren. Die Kämpfer können verschiedene passive Fähigkeiten haben, und sie können auch verschiedene Arten von Kreaturen sein. Ich dachte mir, dass der Dekorateur es mir ermöglicht, zur Laufzeit Verhalten in verschiedenen Kombinationen hinzuzufügen, sodass ich nicht Hunderte von Unterklassen benötige.

Ich bin fast fertig damit, die 15 oder mehr Dekorateure für die passiven Fähigkeiten herzustellen, und beim Testen habe ich etwas entdeckt - einen ziemlich krassen Nachteil für das Dekorateurmuster, von dem ich überrascht bin, dass ich noch nichts gehört habe.

Damit die Dekorateure überhaupt arbeiten können, müssen ihre Methoden beim äußersten Dekorateur aufgerufen werden. Wenn die "Basisklasse" - das umschlossene Objekt - eine ihrer eigenen Methoden aufruft, ist diese Methode nicht die dekorierte Überladung, da der Aufruf des Wrappers nicht "virtualisiert" werden kann. Das gesamte Konzept einer künstlichen Unterklasse bricht zusammen.

Das ist eine große Sache. Meine Kämpfer haben Methoden wieTakeHit die wiederum ihre eigenen nennenDamage Methode. Aber das dekoriertDamage wird überhaupt nicht angerufen.

Vielleicht habe ich das falsche Muster gewählt oder war in seiner Anwendung übereifrig. Haben Sie einen Ratschlag zu einem angemesseneren Muster in dieser Situation oder eine Möglichkeit, diesen Fehler zu umgehen? Der Code, den ich überarbeitet habe, hatte alle passiven Fähigkeiten, die über den gesamten Kampfcode verteilt warenif Blöcke an scheinbar zufälligen Orten, deshalb wollte ich es ausbrechen.

edit: etwas code
public function TakeHit($attacker, $quality, $damage)
{
    $damage -= $this->DamageReduction($damage);

    $damage = round($damage);

    if ($damage < 1) $damage = 1;

    $this->Damage($damage);

    if ($damage > 0)
    {
        $this->wasHit = true;
    }

    return $damage;
}

Diese Methode ist in der BasisCombatant Klasse.DamageReduction undDamage können und werden beide von verschiedenen Dekorateuren außer Kraft gesetzt, zum Beispiel einem Passiven, der den Schaden um ein Viertel verringert, oder einem anderen, der dem Angreifer etwas Schaden zurückwirft.

class Logic_Combatant_Metal extends Logic_Combatant_Decorator
{
    public function TakeHit($attacker, $quality, $damage)
    {
        $actual = parent::TakeHit($attacker, $quality, $damage);

        $reflect = $this->MetalReflect($actual);
        if ($reflect > 0)
        {
            Data_Combat_Event::Create(Data_Combat_Event::METAL_REFLECT, $target->ID(), $attacker->ID(), $reflect);
            $attacker->Damage($reflect);
        }

        return $actual;
    }

    private function MetalReflect($damage)
    {
        $reflect = $damage * ((($this->Attunement() / 100) * (METAL_REFLECT_MAX - METAL_REFLECT_MIN)) + METAL_REFLECT_MIN);
        $reflect = ceil($reflect);

        return $reflect;
    }
}

Aber auch diese Decorator-Methoden werden nie aufgerufen, weil sie nicht von außen, sondern innerhalb der Basisklasse aufgerufen werden.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage