所以假设我有两个抽象类:角色和武器.
abstract class Weapon { public string Name { get; set; } } abstract class Character { public Weapon weapon { get; set; } }
派生类可能是武器中的剑和法杖,以及来自角色的战士和法师等(这都是假设的,与我的实际软件无关!).
每个角色都有一个武器,但是对于每个角色的实现,我都知道它将具有什么样的武器实现.例如,我知道(我想强制执行!)在运行时,每个Warrior实例都会有一个Sword类型的武器.我当然可以这样做:
class Sword : Weapon { public void Draw() { } } class Warrior : Character { public Warrior() { weapon = new Sword(); } }
但是这样,每当我想在Warrior中正确使用我的Weapon对象时,我必须执行一个演员,我相信这不是一个很好的练习.此外,我没有办法防止自己弄乱,也就是说,没有类型安全!
一个理想的解决方案是能够使用Sword武器属性覆盖Warrior类中的武器武器属性,这样我有类型安全性,如果用户使用我的战士作为角色,他仍然可以使用我的剑作为武器.可悲的是,C#似乎不支持这种结构.
所以这是我的问题:这是一种经典的OO问题,有一个名称和一个记录良好的解决方案吗?在那种情况下,我非常想知道问题的名称和解决方案.一些良好阅读材料的链接将非常有用!
如果没有,您会提出什么样的课堂设计,以便以优雅和惯用的方式保持功能并强制实施类型安全?
谢谢阅读!
解决方法
is this some kind of classical OO problem,with a name and a well-documented solution?
你遇到的根本问题是在OO系统中很难为子类添加限制.说“一个角色可以使用武器”,然后“战士是一种只能使用剑的角色”很难在OO系统中建模.
如果你对这背后的理论感兴趣,你会想要寻找“利斯科夫替代原则”. (以及为什么“Square”不是“Rectangle”的子类型的任何讨论,反之亦然.)
然而,有办法做到这一点.这是一个.
interface ICharacter { public IWeapon Weapon { get; } } interface IWeapon { } class Sword : IWeapon { } class Warrior : ICharacter { IWeapon ICharacter.Weapon { get { return this.Weapon; } } public Sword Weapon { get; private set; } }
现在Warrior的公共表面区域有一个永远是剑的武器,但任何使用ICharacter接口的人都会看到IWeapon类型的Weapon属性.
这里的关键是摆脱“是一种特殊的”关系,走向“能履行契约”的关系.而不是说“战士是一种特殊的角色”,而是说“战士是一个可以在需要角色时使用的东西”.
所有这些说,你正在开始一个充满迷人问题的世界,在那里你会发现OO语言实际上代表这些东西是多么糟糕.一旦你开始提出更复杂的问题,例如“当一个战士使用锋利的剑来攻击穿着皮甲的兽人时会发生什么?”,你很快就会发现自己陷入双重调度问题并学习如何用访客模式来解决它. “并发现你有四个类层次结构 – 角色,武器,怪物,盔甲 – 所有这些都有影响结果的子类.虚方法只允许您在一个运行时类型上进行调度,但您会发现需要两个,三个,四个或更多级别的运行时类型调度.
它变得一团糟.考虑不要尝试在类型系统中捕获太多.