最近はかなりパターンを使っていますが、本当に良いかどうかはわかりません。
次のようになります。一連の関数があり、それらをActionFoo、ActionBar、および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();
ActionFoo、ActionBar、ActionZapperは無料の関数ですが、同時にインターフェイスで使用していることに注意してください。また、実行時でも(これが必要な場合)、これらの関数の実装を簡単に切り替えることができます。
このアプローチの利点は、新しいアクション用に個別のクラス構造を作成する必要がなく、Action*関数のコード重複がないことです。また、すべての関数は、complexActionが初期化されている場合にのみスコープに入れることができます。
欠点は、 InterfaceClassオブジェクトでどのAction*関数が使用されているかが明確ではないことだと思います。また、そのようなクラスをdynamic_castして、それが何であるかを判断する機能はありません。
これらはそのようなアプローチの不利な点だけではないのではないかと強く思うので、それについてコメントをお願いします。