文章

享元模式 - Flyweight Pattern

用途

節省記憶體和資源,並提高的效能

classDiagram
  ConcreteFlyweight ..|> IFlyweight
  UnsharedConcreteFlyweight ..|> IFlyweight
  Context ..> IFlyweight
  Context ..> Factory
  Factory ..> IFlyweight
  Client ..> Context
  namespace Flyweight {
    class IFlyweight{
      <<Interface>>
      +Operation()
    }
    class ConcreteFlyweight{
      -Object state
      +Operation()
    }
    class UnsharedConcreteFlyweight{
      -Object state
      +Operation()
    }
    class Factory{
      -Dictionary<string, IFlyweight> flyweights
      +GetFlyweight(string key)
    }
    class Context{
      -Factory factory
      -List<IFlyweight> flyweights
      +CreateFlyweight(Object options)
    }
  }
  class Client{
    +Operation()
  }

例子

當談到享元模式(Flyweight Pattern)時,我們可以以一個生活中的例子來解釋
假設你是一位遊戲開發者,正在開發一個多人射擊遊戲
在這個遊戲中,你需要創建許多不同的角色,包括不同種類的士兵和敵人

使用享元模式,你可以節省記憶體和資源,並提高遊戲的效能
你可以將那些具有共享特徵的角色,例如外觀和行為,提取出來並共用,而不是為每個角色創建一個獨立的物件

舉個例子,假設你有多個士兵角色,它們之間的外觀和行為非常相似,唯一的區別可能只是顏色和武器
在享元模式中,你會創建一個士兵享元工廠,該工廠負責管理和提供士兵物件

當遊戲需要創建士兵時,你可以向享元工廠請求一個士兵物件,並提供所需的參數,例如顏色和武器
享元工廠會檢查是否已經存在具有相同參數的士兵物件,如果存在,則返回該物件的引用,否則創建一個新的士兵物件並將其加入享元池中

這樣一來,不同士兵之間可以共享相同的外觀和行為,只有具有不同參數的部分是獨立的
這樣可以節省大量的記憶體和資源,同時提高遊戲的效能

請注意,享元模式適用於具有大量重複性物件的情況,並且這些物件可以在某些方面共享
它的目標是減少內存使用和提高效能

Product

1
2
3
4
5
// 遊戲角色介面
public interface ICharacter
{
    void Display();
}

Concrete Product

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 具體角色類別
public class Warrior : ICharacter
{
    private string name;
    private int level;

    public Warrior(string name, int level)
    {
        this.name = name;
        this.level = level;
    }

    public void Display()
    {
        Console.WriteLine($"Warrior - Name: {name}, Level: {level}");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Mage : ICharacter
{
    private string name;
    private int level;

    public Mage(string name, int level)
    {
        this.name = name;
        this.level = level;
    }

    public void Display()
    {
        Console.WriteLine($"Mage - Name: {name}, Level: {level}");
    }
}

Factory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 角色工廠
public class CharacterFactory
{
    private Dictionary<string, ICharacter> characters = new Dictionary<string, ICharacter>();

    public ICharacter GetCharacter(string characterType, string name, int level)
    {
        // 檢查角色是否已存在,如果存在則返回該角色
        if (characters.ContainsKey(characterType))
        {
            return characters[characterType];
        }
        else
        {
            // 如果角色不存在,則根據角色類型創建一個新角色並將其添加到字典中
            ICharacter character;
            switch (characterType)
            {
                case "Warrior":
                    character = new Warrior(name, level);
                    break;
                case "Mage":
                    character = new Mage(name, level);
                    break;
                default:
                    throw new ArgumentException($"Invalid character type: {characterType}");
            }
            characters.Add(characterType, character);
            return character;
        }
    }
}

Context

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 使用範例
public class Game
{
    private CharacterFactory characterFactory = new CharacterFactory();

    public void CreateCharacter(string characterType, string name, int level)
    {
        // 從角色工廠獲取角色物件
        ICharacter character = characterFactory.GetCharacter(characterType, name, level);

        // 創建角色並加入遊戲
        // ...
    }
}

Client

1
2
3
4
var game = new Game();

game.CreateCharacter("Mage", "David", 1);
game.CreateCharacter("Warrior", "Marry", 10);

延伸

本文章以 CC BY 4.0 授權