オブジェクト作成の列挙と切り替えステートメントを削除するためのデザインパターンが必要です
-
29-09-2019 - |
質問
私がスポーツゲームを作成しているとしましょう。このゲームには、プレイヤーがプレイ、攻撃、防御などができるさまざまなポジションがあります。
public abstract class Position
{
public abstract string Name
{
get;
}
}
そしてサブクラス...
public class Defender : Position
{
public override string Name
{
get { return "Defender"; }
}
}
等々。これはすべて問題ありません。
しかし今、私はこれらのオブジェクトを作成するために関数が必要です。 Position by position関数が必要です。したがって、可能な解決策の1つは、すべての位置の列挙を作成し、この値を列挙に切り替えて適切なオブジェクトを返す関数に渡すことです。しかし、これは私のコードの臭いアラームを引き起こします。このsoultionは、クラス、列挙、および関数内のスイッチを結び付けます。
public static Position GetByType(Types position)
{
switch(position)
{
case Types.Defender:
return new Defender();
... and further terrible code
どんな解決策を検討する必要がありますか?これはどのデザインパターンですか?
解決
小規模でこれを行う必要がある場合、特に単一の場所に住んでいる場合、スイッチはそれほど悪くありません。
中規模でこれを行う必要がある場合は、内部の改善を少し検討することをお勧めします。スティーブエリンガーの提案は合理的なものです。個人的には、使用することを好みます IDictionary<MyEnum, Action<T>>
アクションが問題のクラスの新しいインスタンスを返す場合。
これを壮大なスケールまたは構成可能なスケールで行う必要がある場合は、おそらくStructureMapやNinjectなどのIOCコントローラーなど、最近で遊んでいるクールな子供たちをチェックする必要があります。
他のヒント
のように聞こえます 工場パターン.
ただし、スイッチケースを持っているのは悪いことではないかもしれません。これにより、列挙/文字列をオンにして正しいタイプのオブジェクトを返すことはありません。 1つの場所で隔離されています.
確かに、あなたが望むのは抽象的な工場です。工場の実装のしやすさは、使用している言語に依存します。たとえば、PHPを使用すると、さまざまなクラス名が表示されるため、クラス名を送信して新しい$ classNameを取り戻すことができます。ただし、他の言語ではこれを許可していません。実際、あなたの言語がこれをしない場合、あなたはすでに工場クラスを作成しています!
Reflectionを使用してPHPが何をするかをシミュレートしたくない限り、実際にエレガントなことはありません。
スイッチに対処する1つの方法は、工場に一連のタイプを宣言してもらい、列挙をアレイにインデックスとして使用させることです。
public abstract class Position {
public abstract string Name {
get;
}
}
public class Defender : Position {
public override string Name {
get { return "Defender"; }
}
}
public class Attacker : Position {
public override string Name {
get { return "Attacker"; }
}
}
public static class PositionFactory {
public enum Types {
Defender, Attacker
}
private static Type[] sTypes = new Type[] { typeof(Defender), typeof(Attacker)};
public static Position GetByType(Types positionType) {
return Activator.CreateInstance(sTypes[(Int32)positionType]) as Position;
}
}