これはプログラミングの共通のテーマです:セットの1つにすぎない値(enum、整数の有限集合の1つ、または可能な文字列値の集合、あるいはいくつかのボタンGUIで)何らかのアクションを実行するための基準として使用されます。単純なアプローチは、スイッチ(原子型の場合)または複雑な型のif/elseチェーンを使用することです。それはあなたが現在やっていることであり、それには何の問題もようがない:、年間であなたを含め、誰でも理解:
if(rules.value(ck[j]) == "1") theWorld.addRule(&AgentMovement);
else if(rules.value(ck[j]) == "2") theWorld.addRule(&AgentEat);
else if(rules.value(ck[j]) == "3") theWorld.addRule(&AgentSleep);
// etc.
else error("internal error: weird rules value %s\n", rules.value(ck[j]));
このパターンの主な利点は、それがクリスタルクリアであることを私の経験でありますすぐに何が起こっていて、どの基準がどの行動につながるかをすぐに見ることができます。驚くべき利点であるデバッグも簡単です。特定のアクションでのみ中断することができます。
主な欠点は、保守性です。さまざまな場所で異なるものを切り替えるために同じ基準(enumなど)が使用されている場合は、新しいenum値が追加された場合など、これらの場所をすべて維持する必要があります。アクションには、サウンド、アイコン、状態変更、ログメッセージなどが付いてくる場合があります。これらが同時に(同じスイッチ内で)発生しない場合は、アクション列挙型(または文字列値に対してif/then/else)で何度も切り替えることになります。その場合、アクションに関連付けられたすべての情報をデータ構造体にバンドルし、アクションをキーとしてマップ/ハッシュテーブルに構造体を配置する方がよいでしょう。すべてのスイッチが単一のコールに崩壊します。
struct ActionDataT { Rule rule; Icon icon; Sound sound; };
map<string, AcionDataT> actionMap
= {
{"1", {AgentMovement, moveIcon, moveSound} }
{"2", {AgentEat, eatIcon, eatSound } } ,
//
};
を使用量は、たとえば、
for(int j = 0; j < ck.size(); j++)
theWorld.addRule(actionMap[rules.value(ck[j])].rule);
、他の場所のようになる:
if(actionFinished(action)) removeIcon(actionMap[action].icon);
これはかなり洗練されて、このようなマップは次のようになりますのコンパイル時の初期化。これは、ソフトウェア設計の2つの原則を示しています。1.「コンピュータ科学のすべての問題は、別のレベルの間接指向で解決できます」(David Wheeler)2.多くの場合、より多くのデータまたはより多くのコードが選択できます。単純なアプローチはコード指向であり、マップアプローチはデータ指向です。
スイッチが複数の状況で発生する場合、その都度データをコーディングすることがメンテナンスの悪夢となるため、データ中心主義アプローチは不可欠です。
データ中心のアプローチでは、新しいアクションが追加されたときに、アクションが使用される場所はどれも触れなければならないことに注意してください。これは必須です。このメカニズムは、仮想メンバ関数の呼び出しに似ています(原則と実装では、実際には)。呼び出しコードは実際に何が行われているのか分からず、実際には興味がありません。責任はオブジェクトに移されます。呼び出しコードは、書かれたときに存在しなかったプログラムのライフサイクルの後半でアクションを実行することがあります。対照的に、多くの明示的なスイッチを持つプログラムと比較すると、アクションが追加されたときに1回の使用ごとに調べる必要があります。
データ中心主義アプローチに含まれる間接参照は欠点ですが、ではという別のレベルで間違いが解決できません。コードはより抽象的になり、デバッグするのが難しくなりにくくなります。
正しい方法はありません。しかし、あなたはそれをすることができます。明らかな方法は 'std :: map'を使うことです。 –
'AgentMovement'は単にシンボルの名前です。コンパイラがその仕事をした後、この名前はもはや存在しません。参照するオブジェクトに名前をマップする必要があります(例えば、 'std :: map'を使って) – user463035818
' theWorld'オブジェクトの型は何ですか? – vcp