Заменить Условный на Полиморфизм - Как справиться, когда ваш тип меняется? - PullRequest
3 голосов
/ 28 февраля 2012

Для личного проекта я работаю над небольшой веб-игрой.

У меня есть класс Card, у которого есть свойство Status, и везде есть операторы case.Я подумал, эй, это отличная возможность для Заменить Условное Полиморфизмом !

Проблема в том, что у меня есть пара методов, которые делают такие вещи:

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.Какие варианты у меня есть?Есть ли стандартный способ сделать это?

Редактировать Тормод установил меня прямо.Я хочу State Pattern .Спасибо всем!

Ответы [ 3 ]

3 голосов
/ 28 февраля 2012

В вашем случае у меня был бы объект 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");
    }
}
2 голосов
/ 28 февраля 2012

Вы можете написать класс Status с полиморфизмом:

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

Каждый метод возвращает статус для перехода или что-либо еще, что вы делаете в case прямо сейчас.И тогда вы можете переопределить эти методы для каждого конкретного статуса.Класс Card не будет полиморфным в этой реализации, но он будет содержать полиморфный член Status.

1 голос
/ 28 февраля 2012

Замена условного выражения полиморфизмом полезна в некоторых случаях, но не ясно, подходит ли это здесь ... по крайней мере, не с прямыми перечислениями.Вы могли бы ввести тип «умного перечисления» вместо MyStatusEnum, где каждое значение знало бы о «следующем» значении - тогда вы не обязательно использовали бы полиморфизм, но вы будут использовать фиксированный наборзначений с большим количеством информации, чем стандартное перечисление.

Другой альтернативой является простой Dictionary<MyStatusEnum, MyStatusEnum>, переходящий от «текущего состояния» к «следующему состоянию».Это действительно зависит от того, что вам нужно сделать.Я подозреваю, что мы не сможем дать очень хороший совет, основываясь только на коде, который вы представили.

...