1

最近はかなりパターンを使っていますが、本当に良いかどうかはわかりません。

次のようになります。一連の関数があり、それらをActionFooActionBar、およびActionZapperと呼びましょう。これらは実装が異なる場合がありますが、通常、これら全体で同じ目的で使用されます。それらは順番に一緒に使用される場合とされない場合があります(つまり、それらのいくつかはスタンドアロンとして使用できます)が、実際にグループ化されている場合もあります。

それらを順番に使用したい場合は、通常2つのオプションがあります。

1)毎回手動で書く

2)クラス階層を作成します。

アプローチ#1:

void SomeActionSequence1()
{
    ActionFoo1(1);
    ActionBar1("Moo");
    ActionZapper1("Moo", 42);
}

void SomeActionSequence2()
{
    ActionFoo4(1);
    ActionBar2("Moo");
    ActionZapper1("Moo", 42);
}

これには欠点があります。

1)状態を保存する機能がなく、これらのアクションに多くのパラメーターを渡す必要があります

2)一貫性のあるインターフェースがなく、オートコンプリートを簡単に使用できません

アプローチ#2

class Base
{
    public:
    Base(){}
    virtual ~Base(){}
    virtual void ActionFoo(int) = 0;
    virtual void ActionBar(string) = 0;
    virtual void ActionZapper(string, int) = 0;
    void ExecuteActionSequence();
};

void Base::ExecuteActionSequence()
{
    ActionFoo(1);
    ActionBar("Moo");
    ActionZapper("Moo", 42);
}

Derived1 : public Base
{
    void ActionFoo(int){/*some inplementation*/};
    void ActionBar(string){/*some inplementation*/};
    void ActionZapper(string, int){/*some inplementation*/};
}

Derived2 : public Base
{
    void ActionFoo(int){/*some inplementation*/};
    void ActionBar(string){/*some inplementation*/};
    void ActionZapper(string, int){/*some inplementation*/};
}

次のように使用します。

Base* actionSequence = new Derived1();
actionSequence->ExecuteActionSequence();

正しい仮想が使用され、2つの小さなことを除いてすべて問題ないようです。

1)拡張性-複雑なアクションごとにクラスを作成する必要があります

2)さらに重要なこと-これらのクラス間で多くの関数が複製されるか、階層ツリーが複雑すぎます

私は、「インターフェイスオブジェクト」パターンを使用した両方のアプローチの「回避」問題のようなものです(名前は私のものであり、適切なものがある可能性があります)

私がしていることはこれです:

class InterfaceClass
{
    public:
    InterfaceClass(){};
    ~InterfaceClass(){};

    void ActionFoo(int i)
    {
        if(fooPlaceholder != 0)
            fooPlaceholder(i);
    }
    void ActionBar(string str)
    {
        if(barPlaceholder != 0)
            barPlaceholder(str);
    }
    void ActionZapper(string str, int i)
    {
        if(zapperPlaceholder != 0)
            zapperPlaceholder(str, i);
    };
    void ExecuteActionSequence();

    std::function<void(int)> fooPlaceholder;
    std::function<void(string)> barPlaceholder;
    std::function<void(string, int)> zapperPlaceholder;
};

void InterfaceClass::ExecuteActionSequence()
{
    ActionFoo(1);
    ActionBar("Moo");
    ActionZapper("Moo", 42);
}

私のアプリケーションでは、次のことを行います。

InterfaceClass complexAction;
complexAction.fooPlaceholder = ActionFoo;
complexAction.barPlaceholder = ActionBar;
complexAction.zapperPlaceholder = ActionZapper;

complexAction.ExecuteActionSequence();

ActionFooActionBarActionZapperは無料の関数ですが、同時にインターフェイスで使用していることに注意してください。また、実行時でも(これが必要な場合)、これらの関数の実装を簡単に切り替えることができます。

このアプローチの利点は、新しいアクション用に個別のクラス構造を作成する必要がなく、Action*関数のコード重複がないことです。また、すべての関数は、complexActionが初期化されている場合にのみスコープに入れることができます。

欠点は、 InterfaceClassオブジェクトでどのAction*関数が使用されているかが明確ではないことだと思います。また、そのようなクラスをdynamic_castして、それが何であるかを判断する機能はありません。

これらはそのようなアプローチの不利な点だけではないのではないかと強く思うので、それについてコメントをお願いします。

4

1 に答える 1

1

ChainofResponsibilityパターンが必要なようです

abstract class Action {
    Action child;
    Action(Action child) { this.child = child; }
    Action() { }

    void doAction(StateContext context);

    void execute(StateContext context) {
       if (child) child.execute(context); 
       doAction(context); 
    } 
}

class ZapAction extends Action {
    ZapAction(String theString, int theValue, Action child) { ... }
    void doAction(Context context) { context.setZap(theString); } 
}


Action actionSequenceAlpha = new ZapAction("", 1, new FooAction()); 
Action actionSequenceBeta = new FooAction(new BarAction(new ZapAction));

利点-新しいアクションを追加するときに、この基本オブジェクトを固定された戦略セットで変更する必要はありません。あらゆる種類の楽しくエキサイティングな方法でアクションをマップできます。各オブジェクトには単一の責任があり、優れた標準パターンです。だから誰もが何が起こっているのか知っています。

もう1つのオプションは、シーケンスをアクションから分離することです。それを継承する3つのアクションを備えたアクションインターフェースを用意します。次にSequence、executeメソッドとリストを持つクラスを作成しますAction

class Action { } 
class FooAction extends Action { }

class Sequence {
    List<Action> actions;
    void execute() {
       foreach (action : actions) action.execute();
    }
}
于 2012-08-09T12:14:32.890 に答える