派生类具有额外状态时的状态模式

时间:2014-09-05 23:52:57

标签: design-patterns state

我使用的语言是C ++,但问题与语言无关。我们说我们有

class State {};

enum StateTypes {MOVEMENT, AFFECTED_BY_SPELL, ..., ANGER, N,
    CARRYING_WEAPON, CASTING_SPELL};

class Base {
    array<stack<State*>, N> states;  // MOVEMENT, AFFECTED_BY_SPELL, ..., ANGER
};

class Derived : public Base {
//    array<stack<State*>, 2> states;  // ??? CARRYING_WEAPON, CASTING_SPELL
};

和Derived比Base更有可能的状态。我需要一个数组中的所有状态堆栈,以便我可以遍历它们。但是,Derived具有Base所具有的所有可能状态以及Base所没有的一些状态,如上所述 - Derived将具有涉及携带武器或施放咒语的状态,这些状态不适用于基地。所以很自然,对于Derived,我想要一个长度为N + 2的状态堆栈数组(在本例中),但同时,我希望Derived继承&#39;状态&#39; Base中的数据成员并使用它。我如何设计这个,以便当Base迭代它的所有状态时它从MOVEMENT迭代到ANGER,而Derived从MOVEMENT迭代到CASTING_SPELL?是给Derived一个单独数组的唯一解决方案,N + 2&gt;陈述数据成员并完全忽略其Base ::状态?或者让Base拥有所有N + 2状态,即使其中一些状态类别在Base中没有任何意义(只有Derived可以携带武器或施放咒语)?必须有更好的方法。

这个问题实际上是一个更通用的问题:派生类如何具有基类容器数据成员的超集容器数据成员,除了将超集移到上面之外,两个容器上的所有操作都以相同的方式执行Base,或者只有在完全忽略Base的容器数据成员时才使用Derived的超集?是否有特殊模式来处理这个问题?

为Derived创建一个容器数据成员,它只包含Base的容器数据成员中没有的元素,然后让操作通过Bases&#39;容器,然后以某种方式继续进入Derived的容器???

class State {};

enum StateTypes {MOVEMENT, AFFECTED_BY_SPELL, ..., ANGER, N,
    CARRYING_WEAPON, CASTING_SPELL};

struct Base {
    array<stack<State*>, N> states;  // MOVEMENT, AFFECTED_BY_SPELL, ..., ANGER
    virtual void foo() {for (State* x : states) {foo_helper();} }
    void foo_helper();
    virtual const array<stack<State*>, N>& getStates() const {return states;}
};

struct Derived : public Base {
    array<stack<State*>, 2> states;  // CARRYING_WEAPON, CASTING_SPELL
    virtual void foo() override {
        const array<stack<State*>, N+2> allStates = Base::states + states merged;
        for (State* x : allStates) {foo_helper();}  // Good idea?
    }
    virtual const array<stack<State*>, N+2>& getStates() const override {
        return Base::states + states merged;  // won't work because of different return type
    }
};

如果Derived有自己的派生类以及它们自己的唯一状态,那么同样的问题,等等......

1 个答案:

答案 0 :(得分:1)

您无法封装Base类及其后代的状态管理。考虑永远不要直接引用状态容器并在内部管理状态。

毕竟,班级的用户只需知道每个堆栈的最后状态(如果我明白了)。

要抓住它们,请使用vector:

class Base {
    vector<stack<State*>> states;  // MOVEMENT, AFFECTED_BY_SPELL, ..., ANGER
    public:
    Base() {
       states.reserve(N);
       states.push_back(....)
    }
    vector<State*> getStates() const {
      vector<State*> rv;
      rv.reserve(N);
      for(stack<State*> & stack: states) {
        rv.push_back(stack.top());
      }
      return rv;
    }
};

struct Derived : public Base {
    Derived() {
       states.reserve(N+2);
       states.push_back(....)
    }
}