我正在阅读关于继承的组合的wiki article,并且在示例中他们使用了抽象类。让我们说你想避免他们完全使用抽象类,只使用具体的类。我想知道,我的例子是正确使用构图。我们假设我有以下IGameobject接口。
public interface IGameObject
{
string Name {get;}
}
以及后续武器界面:
//Note the IGameObject getter
public interface IWeapon
{
int Damage {get; }
IGameObject gameObject {get;}
}
通常,在我的游戏中,武器是-a IGameObject。但是,考虑到我们正在使用合成,根据维基文章,它是有一个关系。
现在,我可以在创建Sword对象时执行此操作:
public class Sword : IWeapon
{
private IWeapon weaponObject;
public Sword(IWeapon weapon)
{
this.weaponObject = weapon;
}
public int Damage
{
get
{
return this.weaponObject.Damage;
}
}
public IGameObject gameObject
{
get
{
return this.weaponObject.gameObject;
}
}
}
我现在可以将剑存放在一个集合中,例如List:
List<IWeapon> weapons = new List<IWeapon>();
weapons.add(swordObj)
仍然可以访问我的IGameObject。
现在,我有3个问题:
IGameObject
界面?IGameObject getter
吗? (原因是,如果我把它存储为IWeapon,没有IGameObject getter,那我怎么能得到IGameObject
的详细信息?)答案 0 :(得分:6)
组合与继承是一个非常重要的原则,但是,就像任何原则一样,它只有在适当应用时才会产生积极的效果。 为了正确应用它,你必须了解它是如何发现的。
C vs I之所以被认为是因为开发人员'在OOP上去了',尤其是在允许多重继承的C ++这样的语言中。正如你想象的那样,设计方面的一切都很快就下滑了。
以下列方式很容易想到这个原则: 我们作为OOD系统设计者希望以最类似于我们想要模仿的域的方式对域对象关系进行建模 - 因此我们需要仔细仔细地查看这些关系。
每当您要继承时,请考虑继承是否密切描述相关实体之间的真实世界关系。
在你的情况下,武器实际上是一个游戏对象,所以继承实际上是一个好主意,并将在此过程中促进多态性。
以下是C vs I如何在您的域中应用的示例:
interface IGameCharacter
{
ICollection<IWeapon> Weapons {get;}
ICollection<IGameCharacter> Party {get;}
}
答案 1 :(得分:1)
你在这里使用的是装饰设计模式。您创建了一个扩展某些超类(IWeapon)的新类。这个类叫做装饰器(Sword)。该类包含与超类相同类型的对象 - 此对象称为decoratee(weaponObject)。一些装饰者的责任转移到decoratee。在实践中,这意味着装饰器在其算法之一中调用至少一个decoratee的方法(在您的情况下,decoratee用于Damage和gameObject)。
这一点是为了避免在decoratee中已经存在的装饰器中重新实现某些行为。如果decoratee已经具有所需的行为,并且您想在装饰器中使用此行为,则装饰器模式是一个不错的选择。
另一个选项是子类化decoratee并继承想要的行为,但是引入了与子类相关的其他问题(紧耦合,除了想要的行为之外还继承了一些不需要的行为,暴露了不应该暴露给decoratee的东西)装饰者等)。如果您想要组合的好处,您必须实现装饰器模式(或类似的模式)而不是子类。但请记住,decoratee的具体类型可以在运行时更改,而这种类型决定了您在装饰器类中将获得的行为。这对于支持在运行时更改行为非常有用,但在实现模式时您也必须注意这一点。
现在,关于装饰器模式在这种情况下是否是正确的选择,我向您提出以下问题:您是否希望您的Sword类(您的装饰器)利用来自IWeapon的另一个子类的某些行为(您的decoratee)你想在运行时改变这种行为吗?如果您对该问题的回答是肯定的,则装饰器模式非常合适。