在这一系列博客文章中,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();
状态由Command
s并根据Rule
s 修改:
...我们制作了一个
Command
名为的Wield
对象,它带有两个游戏状态对象aPlayer
和aWeapon
。当用户向系统发出命令“此向导应使用那把剑”时,该命令将在一组Rule
s 的上下文中进行评估,这会产生一系列Effect
s。我们有一个Rule
说,当玩家尝试挥舞一种武器时,其效果是丢弃了现有武器(如果有的话),而新武器成为了玩家的武器。我们还有另一条规则增强了第一条规则,即当向导尝试挥舞剑时,第一条规则的效果不适用。
我原则上喜欢这个想法,但对如何在实践中使用它有所关注。
似乎没有什么可以通过简单地将on 设置为来阻止开发人员规避Commands
and Rule
的。该属性需要可通过命令访问,因此无法进行设置。Weapon
Player
Weapon
Wield
private set
那么,是什么呢防止开发人员这样做呢?他们只需要记住不要吗?