22

目の前に問題があり、どのデザイン パターンを使用すればよいかわかりません。問題は次のようになります。

「N」個の状態を持つシステムを構築する必要があり、私のシステムは、いくつかの条件に応じて、任意の状態から他の状態に遷移する必要があります。例:条件1で状態1から3へ、条件2で状態1から4へ移動。

ある状態から別の状態への遷移でさえ、2 つ以上の異なる条件で実行できます。

たとえば、状態 1 から状態 3 への遷移は、次の場合に実行できます。
条件 1:「日曜日です」
条件 2:「雨が降っています」
条件 3:「雨と日曜日」
それぞれの条件で、状態 3 での処理は次のようになります。違う。

問題を読みやすく理解できたと思います。親切に助けてください。

どうもありがとう

4

6 に答える 6

41

これは明らかに有限状態マシンのケースですが、組み合わせごとに新しい条件を作成するよりも、条件を組み合わせる方が適切です。州は多くのシナリオで意味をなさない他の州について知っているため、Wikipedia の State パターンの Java の例は好きではありませんでした。from状態、適用可能なcondition(s)、およびto状態を追跡する遷移テーブルは、この問題の処理に役立ちます。

オブジェクト指向の有限状態機械に対する私の 2 セント。オブジェクト指向の面で改善できる点はありますが、アイデアは伝わります。

class Transition {
    State from;
    Set<Condition> conditions;
    State to;
}

class State {
    String state;
}

class Condition {
    String condition;
}

ステート マシンは、上記の型で構築できます。エラーチェックはありませんが、いくつかの条件で次の状態が見つからない場合、例外または何かをスローできます。

class StateMachine {
    List<Transition> transitions;
    State current;

    StateMachine(State start, List<Transition> transitions) {
        this.current = start;
        this.transitions = transitions;
    }

    void apply(Set<Condition> conditions) {
        current = getNextState(conditions);
    }

    State getNextState(Set<Condition> conditions) {
        for(Transition transition : transitions) {
            boolean currentStateMatches = transition.from.equals(current);
            boolean conditionsMatch = transition.conditions.equals(conditions);
            if(currentStateMatches && conditionsMatch) {
                return transition.to;
            }
        }
        return null;
    }
}

そしてテスト実行:

編集:あなたのコメントに基づいて、いくつかの遷移と新しい状態があります:

State one = new State("one");
State two = new State("two");
State three = new State("three");

Condition sunday = new Condition("Sunday");
Condition raining = new Condition("Raining");
Condition notSunday = new Condition("Not Sunday");
Condition notRaining = new Condition("Not Raining");

List<Transition> transitions = new ArrayList<Transition>();
transitions.add(one, new Set(sunday), three);
transitions.add(one, new Set(sunday), two); // <<--- Invalid, cant go to two and three
transitions.add(one, new Set(raining), three);
transitions.add(one, new Set(sunday, raining), three);
transitions.add(one, new Set(notSunday, notRaining), three);

StateMachine machine = new StateMachine(one, transitions);
System.out.print(machine.current); // "one"
machine.apply(new Set(sunday, raining));
System.out.print(machine.current); // "three

かなり大規模なプロジェクトでステート マシンを使用するという苦い経験がありました。問題は複合状態にありました。あなたが言及した複合状態 (日曜日と雨) のように、技術的には、さらに単位状態に分解できる複合状態が存在する可能性があります。これはあなたの状況に当てはまる場合とそうでない場合がありますが、それでも言及する価値があります。その場合は、従来の有限状態マシンを変更し、単一の状態ではなく状態のセットを使用して、開始状態と終了状態を表すのが最善です。N が大きい場合、これは健全性レベルをそのまま維持するのに役立ちます。hotmail フォルダと gmail タグを考えてみてください。遷移表は次のように表されます。

Transition(Set<State> from, Set<Condition> conditions, Set<State> to)
于 2010-01-14T13:02:13.317 に答える
14

これは、有限ステート マシンの典型的な使用方法のように思えます。

つまり、ステート マシンは、システムが取りうるさまざまな状態と、状態から状態へ移行できる条件を記述します。ステート マシンは、英語の説明とまったく同じように記述されます。そして、状態図を使用して正式に記述することができます

コードでは、次のようなステート マシンを作成できます。

 enum State { Init, ShowMenu, ShowMsg, DisplayVideo, Exit };
 State state = State.Init;

 while (state != State.Exit)
 {
      switch(state)
      {
           case State.Init:
                init();
                state = State.ShowMenu;
                break;
           case State.ShowMenu:
                if(lastMenuItemSelected==1) state = State.ShowMsg;
                if(lastMenuItemSelected==2) state = State.DisplayVideo;
                break;
           case State.ShowMsg:
                ....
                break;
           ....
 }

Javaの正確な構文が正しいかどうかはわかりません...私はC#にもっと興味があります

于 2010-01-13T15:24:44.620 に答える
9

状態パターンは機能しませんか?

于 2010-01-13T15:23:50.050 に答える
2

他の人が言ったように、状態マシンは、スイッチを使用した手続き型コードまたは状態パターンを使用した OO コードでモデル化できます。これはおそらくあなたが求めていたものです。

ただし、3 番目の方法は、状態をノードとして、条件を有向エッジとして、実際にグラフとしてコーディングすることです。次に、訪問者パターンを使用して、グラフをさまざまな用途に適用できます。これは、状態や遷移をユーザー定義できる設計に特に適していますが、他の回答で説明されているハードコーディングされた状態マシンよりもメモリを集中的に使用する可能性があります。

于 2010-01-14T12:56:16.353 に答える
1

あなたの例で最初に気づいたのは、State 3 = (State 1 == true && State 2 == true) ということです。これは、より多くの状態が関与する可能性があるため、あまりうまくスケーリングされません。雨が降っているのか、それとも日曜日なのかのみを考慮している場合は、次のような 4 つのタイプの列挙を行うことができます。

enum State { CLEAR_OTHER_DAY, RAINING_OTHER_DAY, CLEAR_SUNDAY, RAINING_SUNDAY }

これにより、コーディング時に switch ブロックで条件を明確に述べることができます。ただし、外が暖かいかどうかも考慮する必要がある場合は、考えられるすべての条件を取得するために、その列挙型にさらに 4 つの値を追加する必要があります。プロジェクトの後半では、現在想定しているよりも多くの条件をコードでキャプチャする必要がある場合があります。

設計パターンに関しては、ウィキペディアにある State パターンとそのJava の例が出発点として適しているように見えます。

ウィキペディアの例には、名前を受け取るStateContextというメソッドを持つクラスがありsetStateます。ここに状態判定ロジックを追加することを提案することを考えましたが、そうするとStateContextクラスが他のクラスの実装の詳細に近づきすぎる必要があります。システムの状態を判断するメソッドを、ある状態から別の状態に移行するための条件を簡単に知ることができるクラスに入れる方がよいでしょう。これにより、プロジェクトを将来変更する必要があり、追跡する状態が増えたり、条件が異なったりした場合でも、ロジックを 1 か所に維持するだけで済みます。

于 2010-01-13T16:04:05.803 に答える