3

C++ モジュールを設計しています。このモジュールは、Request-A、Request-B、Request-C の 3 種類のリクエストを受け取ることができます。
各タイプに対応するハンドラー クラスがあります: RequestHandler-A、RequestHandler-B、および RequestHandler-C (これらはすべて IRequestHandler インターフェイスを実装します)。
各ハンドラーは、その要求を満たすために特定のアクションを実行する必要があります。
たとえば、RequestHandler-A はこれらを順番に実行する必要があります。
Action-1
Action-2
Action-3
Action-4
Action-5

RequestHandler-B はこれらを順番に実行する必要があります:
アクション-1
アクション-3
アクション-5

RequestHandler-C はこれらを順番に実行する必要があります:
Action-4
Action-5

1 つのアクションの結果は、次のアクションで使用されます。

一般的なアクションの実装がハンドラー間で再利用されるように、これらのクラスを設計するのに苦労しています。ここに適用できる設計パターンはありますか? 多分 Template メソッドのパターンが可能性があるかもしれませんが、私にはわかりません。どんな提案でも大歓迎です。

PS: より興味深いものにするために、Action-2 が失敗した場合、別のデータで再試行する必要があるという要件もあります。しかし、私は先のことを考えすぎているのかもしれません。

4

4 に答える 4

4

「一般的な実装」とは、ソリューションが継承とは何の関係もないことを意味します。継承は、実装の再利用ではなく、インターフェースの再利用のためのものです。

共有関数を使用するだけで、共通のコードがあることがわかります。

void action1();
void action2();
void action3();
void action4();
void action5();

struct RequestHandlerA : IRequestHandler {
    virtual void handle( Request *r ) {
        action1();
        action2();
        action3();
    }
};

struct RequestHandlerB : IRequestHandler {
    virtual void handle( Request *r ) {
        action2();
        action3();
        action4();
    }
};

struct RequestHandlerC : IRequestHandler {
    virtual void handle( Request *r ) {
        action3();
        action4();
        action5();
    }
};

static共通関数が単なる内部ヘルパーであると仮定すると、内部リンケージを取得するためにそれらを作成する (または匿名の名前空間を使用する) ことが必要になるでしょう。

于 2013-07-12T15:16:20.890 に答える
2

このようなものをお探しですか?

#include <iostream>

using namespace std;

class Interface{
    public:
        void exec(){
            //prepare things up
            vExec();
            //check everything is ok
        };
        virtual ~Interface(){}
    protected:
        virtual void vExec() = 0;
        virtual void Action0() = 0;
        virtual void Action1(){}
        void Action2(){}
};

void Interface::Action0(){
}

void Action3(){}

class HandlerA : public Interface{
    protected:
        virtual void vExec(){
            Action0();
            Action1();
            Action3();
        }
        virtual void Action0(){
        }
};

class HandlerB : public Interface{
    protected:
        virtual void vExec(){
            Action0();
            Action1();
            Action2();
            Action3();
        }
        virtual void Action0(){
            Interface::Action0();
        }
};

int main()
{
    Interface* handler = new HandlerA();
    handler->exec();
    HandlerB b;
    b.exec();

    delete handler;
}

ご覧のとおり、アクションは、必要に応じて、仮想メンバー、非仮想メンバー、無料の関数、または考えられるものであれば何でもかまいません。

アクションに異なるデータを供給する「追加」機能は、exec() (ジェネリックの場合) または vExec (ハンドラー固有の場合) で実行できます。詳細を教えていただければ、それに応じて例を修正できます。

また、vExec を公開して、exec を取り除くこともできます。例にあるものは、私が最も気に入っている方法です (インターフェースを非仮想にし、仮想関数を非公開にする)。

于 2013-07-12T14:51:55.957 に答える
1

5 つのアクションを実装する 1 つの基本クラスを作成し、そこからハンドラーを派生させることができます。

アクションが互いに十分に分離されている場合は、おそらくそれらを個々の関数またはクラスに分離し、ハンドラーにそれらを呼び出させることができます。

于 2013-07-12T14:45:54.377 に答える