在这一系列博客文章中,Eric Lippert使用向导和战士作为示例描述了面向对象设计中的问题,其中:
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 { }然后添加一些规则:
- 战士只能使用剑。
- 向导只能使用人员。
然后,他继续演示如果您尝试使用C#类型系统强制执行这些规则(例如,让Wizard类负责确保向导只能使用人员)会遇到的问题。您违反了Liskov替代原则,冒着运行时异常的危险,或者最终遇到了难以扩展的代码。
他提出的解决方案是Player类不进行任何验证。它仅用于跟踪状态。然后,不要通过以下方式为玩家提供武器:
player.Weapon = new Sword();状态由Commands并根据Rules 修改:
...我们制作了一个
Command名为的Wield对象,它带有两个游戏状态对象aPlayer和aWeapon。当用户向系统发出命令“此向导应使用那把剑”时,该命令将在一组Rules 的上下文中进行评估,这会产生一系列Effects。我们有一个Rule说,当玩家尝试挥舞一种武器时,其效果是丢弃了现有武器(如果有的话),而新武器成为了玩家的武器。我们还有另一条规则增强了第一条规则,即当向导尝试挥舞剑时,第一条规则的效果不适用。
我原则上喜欢这个想法,但对如何在实践中使用它有所关注。
似乎没有什么可以通过简单地将on 设置为来阻止开发人员规避Commandsand Rule的。该属性需要可通过命令访问,因此无法进行设置。WeaponPlayerWeaponWieldprivate set
那么,是什么呢防止开发人员这样做呢?他们只需要记住不要吗?