4

概要:

状態パターンを使用しているプログラムの設計を改善しようとしています。問題の簡単な説明、クラス図の画像/現在の設計の説明、関連するクラスのヘッダー コードを投稿します。

問題:

プログラムに状態パターンのバリエーションを使用しています。このバリエーションでは、「状態」と「イベント」という 2 つの抽象クラスを利用する「コントローラー」があり、これらのクラスからいくつかの具象型が拡張されています。これら 2 つの抽象クラスは、イベントのタイプと現在の状態に基づいて変化する「イベント」への応答を実行するために使用されます。各状態には、各具体的なイベント タイプを取得するためにオーバーロードされた「ハンドラー」関数があります。

「コントローラー」には、発生した「イベント」(具象クラス) のリストを含む、タイプ「イベント」(抽象クラス) のキューが含まれます。コントローラーは、各イベントを一度に 1 つずつ「処理」し、キューからイベントを取得し、特定のタイプのイベントの状態のハンドラーに渡します。

問題は、正しい型を取得してイベントを状態の適切なハンドラーに渡すために、イベントを正しい具象型にダウンキャストする必要があることです。現在、各具体的なイベント タイプによって実装され、そのイベント タイプを表す整数を返すメソッドをクラス 'state' (getType()) に追加することでこれを実現しています。ただし、この方法は非常に「非エレガント」であり、列挙型を使用して「スイッチ」ブロックと「ダウンキャスト」を駆動することになります。これはあまり良い設計方法ではありません。

このデザインを変更して、イベントの状態への受け渡しをよりエレガントにするにはどうすればよいですか?

クラス図

クラス図

ヘッダー コード

/*****
 * CONTROLLER (driver) CLASS
 */
 queue<event> events; //gets populated by other threads that hold reference to it
 state* currentState;
 vector<state*> allStates;
 allStates.push_back( new state_1(&allStates) ); // passes reference to 'allStates' to each state
 allStates.push_back( new state_2(&allStates) ); //   so that it may return the 'next state'
 ...

while( true ){
    event nextEvent;
    state* nextState;
    if( events.size() > 0 ){
        nextEvent = events.front(); //Get next Event
        events.pop(); //remove from queue
        switch( nextEvent.getType() ){ //determine 'concrete type' based on 'getType method'
            case 1: 
                //Downcast to concrete state type, and let state handle event
                nextState = currentState->handle( *dynamic_cast<event_type_1*>(&nextEvent) ); 
                break;
            case 2:
                state* nextState = currentState->handle( *dynamic_cast<event_type_1*>(&nextEvent) );
                break;
            ...
        }
        //Transition to next state
        currentState = nextState;
    else
        Sleep(5); //
}

/*****
 * EVENT CLASSES
 */
class event{
    public:
        virtual int getType();
}

class event_type_1 : public event{
    public:
        int getType(){ return 1; };
        int specializedFunc1();
        double specializedFunc2();
}

class event_type_2 : public event{
    public:
        int getType(){ return 2; };
        std::string specializedFunc3();
}

/*****
 * STATE CLASSES
 */
class state{
    protected:
        vector<state*>* m_states;
    public:
        state( vector<state*>* p_states ){ m_states = p_states; };
        virtual state* handle( event_type_1 );
        virtual state* handle( event_type_2 );    
}

class state_1 : public state{
    public:
        state* handle( event_type_1 );
        state* handle( event_type_2 );
}

class state_2 : public state{
    public:
        state* handle( event_type_1 );
        state* handle( event_type_2 );
}
4

2 に答える 2

4

抽象メソッドを追加します。

virtual state *transition(state *from) = 0;

イベントへ。

次に、各状態サブクラスで次のように実装します。

state *transition(state *from)
{
    from->handle(this);
}

次に、ループで次のように呼び出します。

nextState = nextEvent->transition(currentState);

編集:

イベントをそのサブクラスでテンプレート化されたテンプレート クラスにすると、イベント クラス自体に遷移を実装できます。

template <class subclass> class event
{
    state *transition(state *from)
    {
        from->handle(dynamic_cast<subclass *>(this));
    }
}
于 2009-10-15T13:59:39.177 に答える
0

ダブルディスパッチは役に立ちませんか?

于 2009-10-15T13:52:57.253 に答える