Flyweightとは
多数のインスタンスを共有することでオブジェクトの数を減らし、
メモリ効率の大幅な改善が見込まれ、メモリ使用量を削減できる設計。
C++
Flyweight
#include <iostream>
#include <map>
#include <string>
#include <vector>
/// <summary>
/// シングルトン
///
/// templateで汎用性強化
/// </summary>
template<typename T>
class Singleton
{
public:
/// <summary>
/// デフォルトコンストラクタ
///
/// コンストラクタは絶対に呼ばない!!
/// </summary>
Singleton() {}
/// <summary>
/// インスタンスを取得する
/// </summary>
static T* GetInstance(void)
{
if (instance == nullptr)
{
// 初回のみ動的確保
instance = new T;
}
return instance;
}
/// <summary>
/// インスタンスを破棄する
/// </summary>
static void DeleteInstance(void)
{
// 削除は動的確保している時のみ
if (instance != nullptr)
{
delete instance;
instance = nullptr;
}
}
private:
static T* instance;
};
template<typename T>
T* Singleton<T>::instance = nullptr;
/// <summary>
/// フライウェイト
/// </summary>
class Flyweight
: public Singleton<Flyweight>
{
// friend : privateへアクセス可能にする
friend class Singleton<Flyweight>;
public:
enum class KIND_OF_ENEMY
{
SLIME,
GOBlIN,
DRAGON,
};
/// <summary>
/// オブジェクト名を取得する
/// </summary>
/// <param name="key">取得するオブジェクトのキー</param>
/// <returns>"\0" = ERROR、"\0"以外 = オブジェクト名</returns>
std::string GetName(KIND_OF_ENEMY key)
{
// map.count(Key)->数
if (namesEnemy.count(key) == 0) return "\0"; // エラー
return namesEnemy[key];
}
/// <summary>
/// オブジェクト名を設定する
/// </summary>
/// <param name="key">設定するオブジェクトのキー</param>
void SetName(KIND_OF_ENEMY key)
{
// map.count(Key)->数
if (namesEnemy.count(key) == 1) return; // 既に存在します
switch (key)
{
case Flyweight::KIND_OF_ENEMY::SLIME:
namesEnemy[key] = "Slime";
break;
case Flyweight::KIND_OF_ENEMY::GOBlIN:
namesEnemy[key] = "Goblin";
break;
case Flyweight::KIND_OF_ENEMY::DRAGON:
namesEnemy[key] = "Dragon";
break;
default:
namesEnemy[key] = "\0";
break;
}
}
private:
std::map<KIND_OF_ENEMY, std::string> namesEnemy;
};
/// <summary>
/// 敵の抽象クラス
/// </summary>
class Enemy
{
public:
/// <summary>
/// コンストラクタ
/// </summary>
Enemy()
{
name = "\0";
}
inline virtual void Output(void) = 0;
std::string name;
};
/// <summary>
/// スライム
/// </summary>
class Slime
: public Enemy
{
public:
/// <summary>
/// コンストラクタ
/// </summary>
Slime()
{
std::cout << "スライムが現れた!!" << std::endl;
name = Flyweight::GetInstance()->GetName(Flyweight::KIND_OF_ENEMY::SLIME);
}
/// <summary>
/// 出力
/// </summary>
inline void Output(void) override
{
std::cout << "オブジェクト名:" << name << std::endl;
}
};
/// <summary>
/// ゴブリン
/// </summary>
class Goblin
: public Enemy
{
public:
/// <summary>
/// コンストラクタ
/// </summary>
Goblin()
{
std::cout << "ゴブリンが現れた!!" << std::endl;
name = Flyweight::GetInstance()->GetName(Flyweight::KIND_OF_ENEMY::GOBlIN);
}
/// <summary>
/// 出力
/// </summary>
inline void Output(void) override
{
std::cout << "オブジェクト名:" << name << std::endl;
}
};
/// <summary>
/// ドラゴン
/// </summary>
class Dragon
: public Enemy
{
public:
/// <summary>
/// コンストラクタ
/// </summary>
Dragon()
{
std::cout << "ドラゴンが現れた!!" << std::endl;
name = Flyweight::GetInstance()->GetName(Flyweight::KIND_OF_ENEMY::DRAGON);
}
/// <summary>
/// 出力
/// </summary>
inline void Output(void) override
{
std::cout << "オブジェクト名:" << name << std::endl;
}
};
int main(void)
{
Flyweight::GetInstance()->SetName(Flyweight::KIND_OF_ENEMY::SLIME);
Flyweight::GetInstance()->SetName(Flyweight::KIND_OF_ENEMY::GOBlIN);
Flyweight::GetInstance()->SetName(Flyweight::KIND_OF_ENEMY::DRAGON);
// 動的配列の作成
std::vector<Enemy*> enemies =
{
new Slime(),
new Slime(),
new Goblin(),
new Goblin(),
new Goblin(),
new Dragon(),
};
//敵の行動
for (auto enemy : enemies)
{
enemy->Output();
}
// 動的配列の解放
enemies.clear();
enemies.shrink_to_fit();
Flyweight::DeleteInstance();
return 0;
}
C#
Flyweight.cs
using System;
using System.Collections.Generic;
using System.Xml.Linq;
/// <summary>
/// シングルトン
///
/// ジェネリックで汎用性強化
/// where T : new()はインスタンス化の保証
/// </summary>
public class Singleton<T> where T : new()
{
private static T instance;
/// <summary>
/// デフォルトコンストラクタ
///
/// private化で複製禁止
/// </summary>
public Singleton() { }
/// <summary>
/// インスタンスを取得する
/// </summary>
public static T GetInstance
{
get
{
// 初回のみ動的確保
return instance ??= new T();
}
}
}
/// <summary>
/// フライウェイト
/// </summary>
public class Flyweight : Singleton<Flyweight>
{
public enum KIND_OF_ENEMY
{
SLIME,
GOBLIN,
DRAGON,
};
private Dictionary<KIND_OF_ENEMY, string> namesEnemy = new Dictionary<KIND_OF_ENEMY, string>();
/// <summary>
/// オブジェクト名を取得する
/// </summary>
/// <param name="key">取得するオブジェクトのキー</param>
/// <returns>"\0" = ERROR、"\0"以外 = オブジェクト名</returns>
public string GetName(KIND_OF_ENEMY key)
{
// map[Key].Length
if (!namesEnemy.ContainsKey(key) || namesEnemy[key].Length == 0) return "\0"; // エラー
return namesEnemy[key];
}
/// <summary>
/// オブジェクト名を設定する
/// </summary>
/// <param name="key">設定するオブジェクトのキー</param>
public void SetName(KIND_OF_ENEMY key)
{
if (namesEnemy.ContainsKey(key))
{
// map[Key].Length
if (namesEnemy[key].Length > 0)
{
return; // 既に存在します
}
}
switch (key)
{
case KIND_OF_ENEMY.SLIME:
namesEnemy[key] = "Slime";
break;
case KIND_OF_ENEMY.GOBLIN:
namesEnemy[key] = "Goblin";
break;
case KIND_OF_ENEMY.DRAGON:
namesEnemy[key] = "Dragon";
break;
}
}
}
/// <summary>
/// 敵の抽象クラス
/// </summary>
public abstract class Enemy
{
public string name;
/// <summary>
/// コンストラクタ
/// </summary>
public Enemy(string _name)
{
name = _name;
}
public abstract void Output();
}
/// <summary>
/// スライム
/// </summary>
public class Slime : Enemy
{
/// <summary>
/// コンストラクタ
/// </summary>
public Slime() : base("Slime")
{
Console.WriteLine("スライムが現れた!!");
}
/// <summary>
/// 出力
/// </summary>
public override void Output()
{
Console.WriteLine($"オブジェクト名:{name}");
}
}
/// <summary>
/// ゴブリン
/// </summary>
public class Goblin : Enemy
{
/// <summary>
/// コンストラクタ
/// </summary>
public Goblin() : base("Goblin")
{
Console.WriteLine("ゴブリンが現れた!!");
}
/// <summary>
/// 出力
/// </summary>
public override void Output()
{
Console.WriteLine($"オブジェクト名:{name}");
}
}
/// <summary>
/// ドラゴン
/// </summary>
public class Dragon : Enemy
{
/// <summary>
/// コンストラクタ
/// </summary>
public Dragon() : base("Dragon")
{
Console.WriteLine("ドラゴンが現れた!!");
}
/// <summary>
/// 出力
/// </summary>
public override void Output()
{
Console.WriteLine($"オブジェクト名:{name}");
}
}
public class Program
{
static void Main()
{
Flyweight.GetInstance.SetName(Flyweight.KIND_OF_ENEMY.SLIME);
Flyweight.GetInstance.SetName(Flyweight.KIND_OF_ENEMY.GOBLIN);
Flyweight.GetInstance.SetName(Flyweight.KIND_OF_ENEMY.SLIME);
// 敵の生成
List<Enemy> enemies = new List<Enemy>
{
new Slime(),
new Slime(),
new Goblin(),
new Goblin(),
new Goblin(),
new Dragon()
};
// 敵の行動
foreach (Enemy enemy in enemies)
{
enemy.Output();
}
}
}