状态模式和封装

AJS*_*S49 5 java oop state encapsulation agents

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

该程序使用多代理系统的代理来代表"超级代理"评估指令(下面的示例).

超级代理可以以两种状态存在,并且如果语句到处检查状态然后执行特定于状态的行为,则会变得混乱.

这是该程序的(非常)简化版本.实际实现有更多的状态特定行为.

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

状态模式非常适合根据GoF模式将特定状态的行为封装到不同的类中(superAgent类将是上下文).然而,有两个问题,其中两个(IMO)打破封装:

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

  2. 状态特定行为需要与非特定状态的行为同步.通过使其公开或使用getter而不暴露锁定对象(在上面的示例instructionLock中),状态和上下文无法共享锁定.公开锁会违反OOP,因为它可能会被包装/扩展类使用.

有没有人对我如何封装这种状态特定的行为有任何建议,请记住上面的例子和两点?

nic*_*083 2

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

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

public void instructionResponseRecievedFromAgent() {
  state.instructionResponseRecievedFromAgent();
}
Run Code Online (Sandbox Code Playgroud)

每个都以这种方式使用双重调度 State来实现:instructionResponseRecievedFromAgent

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();
  }
}
Run Code Online (Sandbox Code Playgroud)

这样做你让每个人State指定要做什么,但由superAgent实例决定如何做。您可以完全访问状态和锁,而无需公开它们。

最后,您在 中实现instructionResponseRecievedFromAgentFromState1和:instructionResponseRecievedFromAgentFromState2superAgent

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
    }
}
Run Code Online (Sandbox Code Playgroud)

请记住,虽然 eventinstructionResponseRecievedFromAgentFromState1instructionResponseRecievedFromAgentFromState2是公共方法(因此State实例可以调用它们),但它们只能在状态模式的上下文中使用。