C# Language
フライウェイトデザインパターンの実装
サーチ…
RPGゲームでのマップの実装
フライウェイトは構造設計パターンの1つです。類似したオブジェクトでできるだけ多くのデータを共有することによって、使用されるメモリの量を減らすために使用されます。この文書はFlyweight DPを正しく使う方法を教えてくれるでしょう。
あなたに簡単な例でそれのアイデアを説明しましょう。あなたがRPGゲームに取り組んでおり、いくつかのキャラクターを含む巨大なファイルをロードする必要があるとします。例えば:
-
#
は草です。あなたはそれを歩くことができます。 -
$
は出発点です -
@
は岩です。あなたはそれを歩くことはできません。 -
%
は宝箱です
マップのサンプル:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@############@@@@@######@#$@@@
@#############@@@######@###@@@
@#######%######@###########@@@
@############################@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
これらのオブジェクトは類似の特性を持つため、マップフィールドごとに個別のオブジェクトを作成する必要はありません。私はフライウェイトを使用する方法を示します。
フィールドが実装するインターフェースを定義しましょう:
public interface IField
{
string Name { get; }
char Mark { get; }
bool CanWalk { get; }
FieldType Type { get; }
}
これで、フィールドを表すクラスを作成できます。何とかそれらを特定する必要があります(私は列挙を使用しました):
public enum FieldType
{
GRASS,
ROCK,
START,
CHEST
}
public class Grass : IField
{
public string Name { get { return "Grass"; } }
public char Mark { get { return '#'; } }
public bool CanWalk { get { return true; } }
public FieldType Type { get { return FieldType.GRASS; } }
}
public class StartingPoint : IField
{
public string Name { get { return "Starting Point"; } }
public char Mark { get { return '$'; } }
public bool CanWalk { get { return true; } }
public FieldType Type { get { return FieldType.START; } }
}
public class Rock : IField
{
public string Name { get { return "Rock"; } }
public char Mark { get { return '@'; } }
public bool CanWalk { get { return false; } }
public FieldType Type { get { return FieldType.ROCK; } }
}
public class TreasureChest : IField
{
public string Name { get { return "Treasure Chest"; } }
public char Mark { get { return '%'; } }
public bool CanWalk { get { return true; } } // you can approach it
public FieldType Type { get { return FieldType.CHEST; } }
}
私が言ったように、私たちは各フィールドに別のインスタンスを作成する必要はありません。フィールドのリポジトリを作成する必要があります。 Flyweight DPの本質は、必要な場合にのみオブジェクトを動的に作成し、リポジトリにはまだ存在しないか、すでに存在する場合はオブジェクトを返すことです。これを処理する簡単なクラスを作成しましょう:
public class FieldRepository
{
private List<IField> lstFields = new List<IField>();
private IField AddField(FieldType type)
{
IField f;
switch(type)
{
case FieldType.GRASS: f = new Grass(); break;
case FieldType.ROCK: f = new Rock(); break;
case FieldType.START: f = new StartingPoint(); break;
case FieldType.CHEST:
default: f = new TreasureChest(); break;
}
lstFields.Add(f); //add it to repository
Console.WriteLine("Created new instance of {0}", f.Name);
return f;
}
public IField GetField(FieldType type)
{
IField f = lstFields.Find(x => x.Type == type);
if (f != null) return f;
else return AddField(type);
}
}
すばらしいです!これでコードをテストできます:
public class Program
{
public static void Main(string[] args)
{
FieldRepository f = new FieldRepository();
IField grass = f.GetField(FieldType.GRASS);
grass = f.GetField(FieldType.ROCK);
grass = f.GetField(FieldType.GRASS);
}
}
コンソールの結果は次のようになります。
Grassの新しいインスタンスを作成しました
ロックの新しいインスタンスを作成しました
しかし、なぜ我々は2回それを取得したい場合、芝生は一度だけ表示されますか?これは、初めてGetField
grassインスタンスをリポジトリに存在しないと呼ぶためです 。作成されましたが、次に草が必要なときは既に存在しているので、返すだけです。