组合优于继承 - 避免抽象 类

Composition Over Inheritance - Avoiding Abstract Classes

我正在读这个 wiki article 关于组合优于继承的文章,在示例中他们使用了抽象 class。假设您想完全避免他们使用抽象的 classes,而只使用具体的 classes。我想知道,我的示例是否正确使用了构图。假设我有以下 IGameobject 接口。

    public interface IGameObject
    {
        string Name {get;}
    }

以及以下武器界面:

    //Note the IGameObject getter
    public interface IWeapon
    {
        int Damage {get; }
        IGameObject gameObject {get;}
    }

通常,在我的游戏中,武器是一个 IGameObject。但是,考虑到我们使用的是组合,根据维基文章,它是 has-a 关系。

现在,我可以在创建 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<IWeapon> weapons = new List<IWeapon>();
weapons.add(swordObj)

并且仍然可以访问我的 IGameObject。

现在,我有 3 个问题:

  1. 我是否正确实施了合成?
  2. 我的 Sword class 是否也应该实现 IGameObject 接口?
  3. 我的 IWeapon 包含 IGameObject getter 可以吗? (原因是,如果我将它存储为 IWeapon,没有 IGameObject getter,那么我如何获得 IGameObject 的详细信息?)

组合与继承是一个需要掌握的非常重要的原则,但是,与任何原则一样,只有正确应用它才会产生积极的效果。 为了正确应用它,您必须了解它是如何被发现的。

C vs I 被认为是因为开发人员 'went to town' OOP,尤其是在 C++ 等允许多重继承的语言中。正如您想象的那样,在设计方面,一切都很快走下坡路。

通过以下方式很容易想到这个原则: 作为 OOD 系统设计者,我们希望以最类似于我们想要模拟的领域的方式对领域对象关系进行建模 - 因此我们需要仔细仔细地查看这些关系。

每当您要继承时,请务必考虑继承是否紧密描述了相关实体之间的真实世界关系。

在你的例子中,武器实际上是一个游戏对象,所以继承实际上是一个好主意,并且会在这个过程中促进多态性。

以下是 C 与 I 如何在您的域中应用的示例:

interface IGameCharacter
{
  ICollection<IWeapon> Weapons {get;}
  ICollection<IGameCharacter> Party {get;}
}

你在这里使用的是装饰器设计模式。你创建了一个新的 class 来扩展一些 superclass (IWeapon)。这个class就叫做装饰器(剑)。 class 包含一个与 superclass 相同类型的对象——这个对象被称为 decoratee (weaponObject)。装饰者的部分责任转移给了装饰者。在实践中,这意味着装饰器在其算法之一中至少调用装饰者的一种方法(在您的情况下,装饰者用于 Damage 和 gameObject)。

这样做的目的是避免在装饰器中重新实现装饰器中已经存在的某些行为。如果被装饰者已经有要求的行为,而你想在你的装饰器中有这个行为,那么装饰器模式是一个不错的选择。

另一种选择是子class装饰对象并继承想要的行为,但这会引入与子class相关的其他问题(紧耦合,除了继承一些不需要的行为想要的行为,从被装饰者那里暴露出不应该暴露给装饰者的东西,等等)。如果你想要组合的好处,你必须实现装饰器模式(或类似的模式)而不是 subclassing。但请记住,被装饰者的具体类型可以在运行时改变,正是这种类型决定了你将在装饰器中获得什么行为class。这对于在运行时支持更改行为非常有用,但在实现模式时也必须注意这一点。

现在,至于在这种情况下装饰器模式是否是正确的选择,我向您提出以下问题:您是否希望您的 Sword class(您的装饰器)利用来自IWeapon 的另一个子 class(您的装饰者),您是否希望能够在运行时更改此行为?如果你对这个问题的回答是肯定的,那么装饰器模式就很合适。