3 Stimmen

Ersetzen Sie Conditional durch Polymorphismus - Wie gehen Sie vor, wenn sich Ihr Typ ändert?

Für ein persönliches Projekt arbeite ich an einem kleinen webbasierten Spiel.

J'ai un Card Klasse, die eine Status Eigenschaft, und es gibt überall Case-Anweisungen. Ich dachte: "Hey, das ist eine tolle Gelegenheit für Konditional durch Polymorphismus ersetzen !

Das Problem ist, dass ich ein paar Methoden habe, die so etwas machen:

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

Beim Refactoring in der neuen NormalCard Klasse, überschreibe ich die ChangeStatus Methode wie folgt:

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

Das Problem ist dieses Objekt der NormalCard hat einen Status von Underwater . Ich kann den Typ nicht neu zuordnen this und ich möchte nicht wirklich die Rückgabe der Methoden von void a CardBase . Welche Möglichkeiten habe ich? Gibt es eine Standardmethode, um dies zu tun?

Editar Tormod hat mich aufgeklärt. Ich will die Zustand Muster . Danke an alle!

3voto

millimoose Punkte 37843

In Ihrem Fall würde ich eine Card Objekt, das eine CardStatus Eigentum. Die Subtypen von CardStatus den vorherigen Enum-Werten entsprechen. Überarbeitung des Verhaltens, das vom aktuellen Status abhängt mit Ausnahme des Zustandsübergangs innerhalb der CardStatus-Subtypen zu sein.

Der Zustandsübergang in Ihrem ersten Beispiel sollte, IMO, innerhalb der Card Objekt. Die Zustandsänderung ist eher ein Verhalten der Karte als des Zustandsobjekts. Was Sie tun können, ist die CardStatus-Objekte sagen Ihnen, welcher Zustand nach einem Ereignis zu übergehen.

Ein grobes Beispiel: (natürlich gibt es noch viele weitere Variationen, die man verwenden könnte).

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);
    }
}

Status-Implementierungen

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");
    }
}

2voto

Ilya Kogan Punkte 21256

Sie könnten die Status Klasse mit Polymorphismus:

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

Jede Methode gibt den Status zurück, in den man wechseln kann, oder alles andere, was man in einer case gerade jetzt. Und dann können Sie diese Methoden für jeden spezifischen Status außer Kraft setzen. Die Card Klasse wird mit dieser Implementierung nicht polymorph sein, aber sie wird eine polymorphe Status Mitglied.

1voto

Jon Skeet Punkte 1325502

Das Ersetzen einer Bedingung durch Polymorphismus ist in manchen Fällen nützlich, aber es ist nicht klar, ob es hier angemessen ist... zumindest nicht bei reinen Enums. Sie könnten einen "intelligenten Enum"-Typ einführen, anstatt MyStatusEnum wenn jeder Wert über den "nächsten" Wert Bescheid wüsste - dann würde man nicht unbedingt Polymorphismus verwenden, aber man würde einen festen Satz von Werten mit mehr Informationen als eine Standard-Enum verwenden.

Eine weitere Alternative ist eine einfache Dictionary<MyStatusEnum, MyStatusEnum> vom "aktuellen Status" zum "nächsten Status" zu wechseln. Es hängt wirklich davon ab, ob Sie noch mehr tun müssen. Ich vermute, dass wir nicht in der Lage sind, anhand des von Ihnen vorgelegten Codes einen guten Rat zu geben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X