私は最近 Java アプリケーションを開発しており、GoF の状態パターンに従ってコードを整理しようとしています。
このプログラムは、マルチエージェント システムのエージェントを使用して、「スーパー エージェント」に代わって命令を評価します (以下の例)。
スーパー エージェントは 2 つの状態で存在することができ、状態をチェックしてから状態固有の動作を実行する 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 クラスがコンテキストになります)。ただし、2 つの問題があり、どちらも (IMO) カプセル化を破ります。
ほとんどの状態固有の動作では、スーパー エージェントのプライベート メンバー (上記の例では、instructionData) を変更する必要があります。メンバーには、おそらくアクセスできないはずのデータが含まれており、ラッピング クラスに対して変更可能であってはなりません。
状態固有の動作は、状態固有ではない動作と同期する必要があります。ロック オブジェクト (上記の例の instructionLock) を公開するかゲッターを使用して公開しないと、状態とコンテキストはロックを共有できません。ロックを公開すると、ラップ/拡張クラスで使用される可能性があるため、OOP に違反します。
上記の例と2つの点を念頭に置いて、この状態固有の動作をカプセル化する方法について誰か提案がありますか?