1

私は単純なステート マシンを持っていましたが、現在は多くの特殊なケースから干渉を受けています。

最初に:

void state(SomeObject o) {
   doStep1();
   doStep2();
   doStep3();
}

ここで、あるオブジェクトに type というフィールドがありました。たとえば、typeA、typeB、typeC などです。typeC には特別な処理が必要でした。

   void state(SomeObject o) {
       doStep1();  
       doStep2();
       if (o.type == typeC) { o.doFoo(); } 
       doStep3();
       if (o.type == typeC) { o.doFoo(); } 
    }

明らかに、このコードは拡張可能でも壊れやすいものでもありません。私は typeD と呼ばれる 4 番目のタイプを持っています。これは if-else を追加するだけです。そのような場合に使用するパターンはどれですか? 多態性を使用する場合、タイプ ABC と D の 4 つの実装を持つインターフェイス SomeObject を想定すると、A と B の doFoo() の実装が空になるのではないかと心配しますが、これは良くありません。良いデザインパターンはありますか?

4

1 に答える 1

6

stateロジックは、柔軟性がないことを既に示したとおりです。たとえば、一部のオブジェクトに対して異なる順序で操作を実行する必要がある場合 (3->1->2)、問題はさらに複雑になる可能性があります。

動作は主にSomeObject型に依存するため、「クリーンな」アプローチの 1 つは、各オブジェクトを一連の構成可能なコマンド (コマンド パターン + コンポジット/デコレータ) に変換することだと思います。

/* Declare an interface for executing an operation */
public interface Command
{
    public void execute();
    public Command setNext();
    public Boolean hasNext();
}
/* Abstract class providing compose-ability and chaining behavior for its children.
*/
public abstract class BaseCommand implements Command
{
    private Command next;

    public Boolean hasNext()
    {
        return next != null;
    }
    public Command setNext(Command nextC)
    {
        next = nextC;
        return nextC;
    }
    public void execute(){
        executeImpl();
        if(hasNext()) next.execute();
    }

    public abstract void executeImpl();
}

これで、特定の処理に対応する一連のコマンドを定義できます (それぞれが状態メソッドの特定の「行」/ステップに直接マップされます)。

public class Step1Command extends BaseCommand
{
    // If we need access to the SomeObject instance we can define a dependecy on it
    // ex. through a constructor

    //The necessary processing goes here
    public void executeImpl(){
         doStep1();
    }
}

最後に、オブジェクトを一連のコマンドに変換する必要があります。これは、ファクトリ クラスを介して実現できます。

public class CommandFactory
{

    //The necessary processing goes here
    public Command create(SomeObjectA typeA){
         Command firstCommand = new Step1Command(typeA);
         Command secondCommand = new Step2Command(typeA);
         //....
         Command lastCommand = new StepXCommand(typeA);
         //We can easily switch the order of processing for a particular object
         fistCommand.setNext(secondCommand)
                    //...
                    .setNext(lastCommand);

         return firstCommand;
    }
}

あなたのコードは今どのように見えますか?

CommandFactory cFactory = new CommandFactory();
void state(SomeObject o) {
   Command command = cFactory.create(o);
   command.execute();
}

それで、付加価値は何ですか(これはやり過ぎのように見えるかもしれません)?

  1. stateオブジェクトの種類に応じた処理は、メソッドから離れています。メソッドのオーバーロード + 継承により、if/else をバイパスできるようになります。

  2. 必要な処理 () の順序を簡単に入れ替えることができるため、ロジックが柔軟になります。

  3. 新しい SomeObject 実装処理を追加しても、既存のコードは変更されません (保守性 + 拡張性)

于 2013-11-12T10:12:35.000 に答える