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

状态模式和封装

  •  6
  • AJS49  · 技术社区  · 11 年前

    我最近一直在开发一个Java应用程序,并试图遵循GoF的状态模式来整理代码。

    该程序使用多智能体系统的代理来代表“超级代理”评估指令(示例如下)。

    超级代理可以存在于两种状态,到处都有if语句检查状态,然后执行特定于状态的行为,这会变得很混乱。

    这是一个(非常)简化的程序版本。实际的实现有许多特定于状态的行为。

    public class superAgent
    {
        //the state of the super agent
        private States state;
    
        //Contains information related to the operation of exampleClass. This should not be exposed through mutator methods.
        private HashMap<String, SpecificInstructionData> instructionData
    
        private LinkedBlockingQueue<ExampleInstruction> exampleQueue
    
        private final Object instructionLock = new instructionLock
    
        public enum States
        {
            STATE1,
            STATE2;
        }
    
        public void setState(state s)
        {
            state = s
        }
    
        //Called by a thread that continuously takes from the queue 
        private void runningThread()
        {
            while(isRunning)
            {
                synchronized(instructionLock)
                {
                    ExampleInstruction ei = exampleQueue.take();
                    //Add some data about the instruction into instructionData
                    //send the instruction to an available agent
                }
            }
        }
    
        public void instructionResponseRecievedFromAgent()
        {
            if(state == States.STATE1)
            {
                doState1Behavior();
            }
            else if(state == States.STATE2)
            {
                doState2Behavior();
            }
        }
    
        private void doState1Behavior()
        {
            synchronized(instructionLock)
            {
                //make state specific modifications to instructionData
            }
        }
    
        private void doState2Behavior()
        {
            synchronized(instructionLock)
            {
                //make state specific modifications to instructionData
            }
        }
    }
    

    状态模式非常适合根据GoF模式将特定状态的行为封装到不同的类中(superAgent类将是上下文)。然而,存在两个问题,这两个问题(IMO)都破坏了封装:

    1. 大多数特定于状态的行为都需要对超级代理的私有成员(在上面的示例中,instructionData)进行更改。成员包含可能不应访问的数据,并且 肯定 对于包装类不应该是可变的。

    2. 特定于状态的行为需要与非特定于州的行为同步。如果不通过公开或使用getter来公开锁对象(在上面的示例说明lock中),则状态和上下文就无法共享锁。公开锁违反了OOP,因为它可能被包装/扩展类使用。

    考虑到上面的例子和两点,有人对我如何封装这种特定于状态的行为有什么建议吗?

    1 回复  |  直到 5 年前
        1
  •  2
  •   nick2083    11 年前

    您可以通过使用来解决这两个问题 Double Dispatch 在状态实例和 superAgent 实例,以避免破坏封装。

    假设您已经实施了状态模式。 instructionResponseRecievedFromAgent 看起来像:

    public void instructionResponseRecievedFromAgent() {
      state.instructionResponseRecievedFromAgent();
    }
    

    每个 State 机具 说明收到代理的响应 以这种方式使用双重调度:

    abstract class State {
      abstract void instructionResponseRecievedFromAgent();
    }
    
    class State1 extends State {
      void instructionResponseRecievedFromAgent() {
        // instance variable
        agent.instructionResponseRecievedFromAgentFromState1();
      }
    }
    
    class State1 extends State {
      void instructionResponseRecievedFromAgent() {
        // instance variable
        agent.instructionResponseRecievedFromAgentFromState2();
      }
    }
    

    这样做,你让每一个 状态 具体说明 什么 要做,但是 超级代理 决定的实例 怎样 做到这一点。你可以完全访问州和锁,而无需将其公开。

    最后,您同时实现了 instructionResponseRecievedFromAgentFromState1 instructionResponseRecievedFromAgentFromState2 在里面 超级代理 :

    public void instructionResponseRecievedFromAgentFromState1() {
        //this is doState1Behavior original implementation
        synchronized(instructionLock)
        {
            //make state specific modifications to instructionData
        }
    }
    
    public void instructionResponseRecievedFromAgentFromState2() {
        //this is doState1Behavior original implementation
        synchronized(instructionLock)
        {
            //make state specific modifications to instructionData
        }
    }
    

    不过要记住,event 指令从代理接收到的响应从状态1 指令从代理接收到的响应从状态2 是公共方法(因此 状态 实例可以调用它们),它们只能在State Pattern的上下文中使用。