状态模式和封装

时间:2013-10-30 17:50:01

标签: 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
        }
    }
}

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

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

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

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

1 个答案:

答案 0 :(得分:1)

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

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

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

每个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();
  }
}

执行此操作,您可以让每个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
    }
}

请注意,尽管instructionResponseRecievedFromAgentFromState1instructionResponseRecievedFromAgentFromState2是公共方法(因此State实例可以调用它们),但它们仅用于上下文国家格局。