用多态替换条件 - 如何处理类型更改?

时间:2012-02-28 15:34:55

标签: c# refactoring polymorphism

对于个人项目,我正在开发一款基于网络的小游戏。

我有一个Card类,它具有Status属性,并且在整个地方都有case语句。我想,嘿,Replace Conditional with Polymorphism这是一个很好的机会!

问题是,我有几种方法可以做这样的事情:

public class Card
{
    public void ChangeStatus()
    {
      switch (Status)
      {
        case MyStatusEnum.Normal:
          Status = MyStatusEnum.Underwater;
          break;
        case MyStatusEnum.Underwater:
          Status = MyStatusEnum.Dead;
          break;
        // etc...
      }
    }
}

在新NormalCard课程中重构时,我会覆盖ChangeStatus这样的方法:

public override void ChangeStatus()
{
    base.Status = MyStatusEnum.Underwater;
}

问题是NormalCard的此对象的状态为Underwater。我无法重新分配this的类型,我真的不想将方法的返回值从void更改为CardBase。我有什么选择?有没有一种标准的方法呢?

编辑 Tormod让我直截了当。我想要State Pattern。谢谢大家!

3 个答案:

答案 0 :(得分:3)

在您的情况下,我有一个包含Card属性的CardStatus对象。 CardStatus的子类型对应于先前的枚举值。重构行为取决于当前状态,但状态转换除了在CardStatus子类型内。

第一个示例中的状态转换IMO应保留在Card对象中。状态变化感觉更像是包含卡的行为而不是状态对象。您可以做的是让CardStatus对象告诉您在事件发生后要转换到的状态。

一个粗略的例子:(显然可以使用更多的变体。)

API

interface ICardStatus {
    ICardStatus NextStatus(Card card);

    void DoStuff(Card card);
}

class Card {
    ICardStatus Status = new NormalCardStatus();

    void DoStuff() {
        Status.DoStuff(this);
    }

    void ChangeStatus() {
        Status = Status.NextStatus(this);
    }
}

状态实施

class NormalCardStatus : ICardStatus {
    ICardStatus NextStatus(Card card) {
        return new UnderwaterCardStatus();
    }

    void DoStuff(Card card) {
        // ...
    }
}

class UnderwaterCardStatus : ICardStatus {
    ICardStatus NextStatus(Card card) {
        return new DeathStatus();
    }

    void DoStuff(Card card) {
        // ...
    }
}

class DeathCardStatus : ICardStatus {
    ICardStatus NextStatus(Card card) {
        // ...
    }

    void DoStuff(Card card) {
        throw new Exception("Cannot do anything while dead");
    }
}

答案 1 :(得分:2)

您可以使用多态性编写Status类:

class Status
{
    Status GetNextStatusWhenFooHappens() {}
    Status GetNextStatusWhenBarHappens() {}
    Status GetNextStatusWhenBloopHappens() {}
}

每个方法都会立即返回要移动到的状态,或者您在case中执行的任何其他操作。然后,您可以为每个特定状态覆盖这些方法。 Card类不会对此实现具有多态性,但它将保留多态Status成员。

答案 2 :(得分:1)

在某些情况下,用多态替换条件很有用,但不清楚它在这里是否合适......至少不是直接枚举。您可以引入“智能枚举”类型而不是MyStatusEnum,其中每个值都知道“下一个”值 - 那么您不一定会使用多态,但使用一组固定的值,其信息比标准枚举更多。

另一种方法是让一个简单的Dictionary<MyStatusEnum, MyStatusEnum>从“当前状态”变为“下一个状态”。这真的取决于你是否还需要做更多的事情。我怀疑我们真的不能仅根据您提供的代码提供非常好的建议。