代码之家  ›  专栏  ›  技术社区  ›  zar

使用状态模式来维护当前选定的对象是否合适?

  •  0
  • zar  · 技术社区  · 6 年前

    状态模式的一个典型场景涉及的状态大部分是不同的,比如 closed_connection_state open_connection_state . 在我的例子中,所有的状态本质上是相同的,但是操作需要应用到当前选择的对象。

    class Object
    {
        std::string _name;
    public:
        Object(std::string name) : _name(name)
        {
    
        }
    
        void Perform()
        {
            std::cout << _name << " Perform called\r\n";
        }
    };
    
    class CurrentObject
    {
        Object* _a;
        Object* _b;
        Object* _current;
    
    public:
    
        CurrentObject(Object* a, Object* b) : _a(a), _b(b)
        {
            _current = a;
        }
    
        void Perform()
        {
            _current->Perform();
    
            // Update _current logic goes here, lets just switch
            // the state whenever `Perform` is called.
            if (_current == _a)
                _current = _b;
            else
                _current = _a;
        };
    
    };
    
    int main()
    {
        Object a("a"); // program can be in a state when `a` is the current object.
        Object b("b"); // or b can become the current object as result of an operation on current object
    
        CurrentObject current(&a, &b); // it assigns the defaults
    
        // assume Perform() does its thing but it also needs to change the current selected object.
        // In this example, we assumes the current selection object is always swapped.
        current.Perform(); // operates on `a`, the default
        current.Perform(); // operates on `b` due state changed in above line
        current.Perform(); // operates on `a` doe to state changed in above line again
    }
    
    1 回复  |  直到 4 年前
        1
  •  2
  •   Bill K    6 年前

    这绝对是一个合理的做法,如果您的状态成倍增加(就像状态机倾向于这样),这可能会变得有点难以维护,但实际上这是一个非常好的OO风格的状态机实现。

    对于扩展,您可能还想“命名”您的状态并将它们放入哈希表中,一旦它扩展(记住,在编程中您有1个或多个)添加新的状态不会对您的状态机进行代码更改--但我假设您已经有了类似的东西,并且只是针对这个问题缩小了它。

    还要注意,要切换不希望直接执行的状态(如示例所示),可能需要一个方法(setState)在perform方法返回时更改状态,而不是在perform方法本身中或在其运行时更改状态。实际上,您可以让perform返回一个字符串,指示它的下一个所需状态。。

    根据评论编辑:

    我给你们的州命名的意思是:

    class CurrentObject
    {
        Object* _a;
        Object* _b;
        Object* _current;
        ...
    

    你可能会有这样的想法(请原谅我的java语法,C不是我的主要语言,但我知道它在功能上非常相似)

    class CurrentObject
    {
        Hashtable states=new Hashtable();
        Object* _current;
    
        public addState(String stateName, Object* state)
        {
            states.put(stateName, state)
        }
    
        public void Perform()
        {
            String nextState = _current->Perform();
            if(nextState != null)
                setState(nextState);
        }
        public void setState(String stateName)
        {
            _current = states.get(stateName);
        }
    
    }
    

    您的呼叫代码将执行以下操作:

    currentObject = new CurrentObject()
    currentObject.addState("state a", _a);
    currentObject.addState("state b", _b); 
    currentObject.setState("state a");
    currentObject.perform();
    ...
    

    我忽略了很多初始化和错误检查。

    您的状态机当前只有一个事件:“Perform()”。您可能会发现您需要其他事件,这些事件会使事情稍微复杂一些(在java中,我可能会使用反射或注释来解决这个问题,不确定C#将如何做到这一点)。