0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C++】Flyweight(デザインパターン)

Last updated at Posted at 2025-01-29

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();
        }
    }
}
0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?