In dieser Reihe von Blog-Posts beschreibt Eric Lippert ein Problem im objektorientierten Design am Beispiel von Zauberern und Kriegern.
abstract class Weapon { }
sealed class Staff : Weapon { }
sealed class Sword : Weapon { }
abstract class Player
{
public Weapon Weapon { get; set; }
}
sealed class Wizard : Player { }
sealed class Warrior : Player { }
und fügt dann ein paar Regeln hinzu:
- Ein Krieger kann nur ein Schwert benutzen.
- Ein Assistent kann nur einen Stab verwenden.
Anschließend demonstriert er die Probleme, auf die Sie stoßen, wenn Sie versuchen, diese Regeln mithilfe des C # -Systems durchzusetzen (z. B. indem Sie die Wizard
Klasse dafür verantwortlich machen, dass ein Assistent nur einen Stab verwenden kann). Sie verstoßen gegen das Liskov-Substitutionsprinzip, riskieren Laufzeitausnahmen oder erhalten Code, der schwer zu erweitern ist.
Die Lösung, die er findet, ist, dass die Player-Klasse keine Validierung durchführt. Es wird nur zum Verfolgen des Status verwendet. Dann, anstatt einem Spieler eine Waffe zu geben durch:
player.Weapon = new Sword();
Zustand wird durch Command
s und gemäß Rule
s geändert :
... wir machen ein
Command
Objekt namensWield
, das zwei Spielstatusobjekte nimmt, aPlayer
und aWeapon
. Wenn der Benutzer einen Befehl an das System ausgibt, "dieser Assistent sollte dieses Schwert führen", wird dieser Befehl im Kontext einer Menge vonRule
s ausgewertet , die eine Folge vonEffect
s erzeugt. Wir haben eineRule
, die besagt, dass, wenn ein Spieler versucht, eine Waffe einzusetzen, die vorhandene Waffe, falls vorhanden, fallen gelassen wird und die neue Waffe zur Waffe des Spielers wird. Wir haben eine andere Regel, die die erste Regel stärkt, die besagt, dass die Auswirkungen der ersten Regel nicht gelten, wenn ein Zauberer versucht, ein Schwert zu führen.
Ich mag diese Idee im Prinzip, habe aber Bedenken, wie sie in der Praxis angewendet werden könnte.
Nichts scheint einen Entwickler daran zu hindern, das Commands
und Rule
s zu umgehen, indem er einfach das Weapon
auf a setzt Player
. Die Weapon
Eigenschaft muss über den Wield
Befehl zugänglich sein , damit sie nicht erstellt werden kann private set
.
Was hindert einen Entwickler daran? Müssen sie sich nur daran erinnern, es nicht zu tun?