モード (通常は列挙型で表される) をコマンドの実装とその関係から切り離す方法は? モード スイッチ (int、enum、string、...) とそのコマンド呼び出しの間の緩やかな結合を説明する良いパターンですか? 構成を介してモードを追加したいので、これは(動的に)簡単に拡張可能でなければなりません(プログラミングなしで)。コマンド パターン (C#/.Net の ICommand) は既に知っています。それはコマンドの辞書とそれに関連するモード番号かもしれませんが、切り替えロジックはどうでしょうか?
1 に答える
リクエスト (入力) とその応答 (出力) を解決する戦略からコンテキスト (切り替え決定、パラメータ) を切り離すことができます。
たとえば、ジェネリックを使用して、1 つのコード ベースでさまざまなケースでこの問題を解決できます。たとえば、戦略はその種類の入力と出力、および評価する条件によって定義されます。
public class Strategy<TInput, TOutput>
{
public Predicate<TInput> Condition { get; private set; }
public Func<TInput, TOutput> Result { get; private set; }
public Strategy(Predicate<TInput> condition, Func<TInput, TOutput> result)
{
Condition = condition;
Result = result;
}
public TOutput Evaluate(TInput input)
{
return Condition(input) ? Result(input) : default(TOutput);
}
}
コンテキストにはさまざまな戦略があり、戦略に責任を求めます (条件が整っていれば、要求の結果を計算できます)。
public class Context<TInput, TOutput>
{
private List<Strategy<TInput, TOutput>> Strategies { get; set; }
public Context(params Strategy<TInput, TOutput>[] strategies)
{
Strategies = strategies.ToList();
}
public TOutput Evaluate(TInput input)
{
var result = default(TOutput);
foreach (var strategy in Strategies)
{
result = strategy.Evaluate(input);
if (!Equals(result, default(TOutput)))
break;
}
return result;
}
}
入力文字列を出力文字列に解決する必要がある簡単な例を見てみましょう (switch ケースなど)。
1. アクションを定義します(簡単にするために、これを以下に示します (ご覧のとおり、すべてのメソッドには独自のロジックと懸念事項があります)。
private static string Move(string s)
{
if (s == "move")
return "doMove"; // here could be some more action...
return null;
}
private static string Query(string s)
{
if (s == "point")
return "queryPoint"; // here could be some more action...
return null;
}
2.評価を実行する条件を定義します (ICommand の CanExecute など)。
private static bool Condition(string s)
{
return !string.IsNullOrEmpty(s); // could eval different states, values
}
... さらに条件を定義することもできます (例: 戦略ごとに 1 つの条件評価関数) が、ここでは 1 つだけを使用します。
3. コンテキストに必要な戦略オブジェクトを作成します (これらはスイッチのさまざまなパスを象徴し、結果を示します)。
var navigate = new Strategy<string, string>(Condition, Move);
var query = new Strategy<string, string>(Condition, Query);
2. コンテキストを初期化します(スイッチ本体を入力で表します)。
var strategies = new List<Strategy<string, string>> {navigate, query};
var context = new Context<string, string>(strategies.ToArray());
3. それらをコードに接続します(たとえば、ボタン クリックで「切り替え」を実行します)。
private void ButtonClick(object sender, RoutedEventArgs e)
{
var message = context.Evaluate(textBox1.Text);
if (message != null) MessageBox.Show(message); // display result
}
... それでおしまい。
コンテキストは、適切な戦略を提供します (適切なアクションを実行したり、いくつかのアクション (ICommand など) を実行するために必要な「ツール」を提供したりできます)。