概要
Flyweight(フライウェイト)パターンは、
多数のオブジェクトを効率よく扱うために、共通する状態(内部状態)を共有し、必要な差異(外部状態)のみを個別に保持する設計パターンである。
UI要素、文字オブジェクト、グラフィックス、粒子エンジンなど、「似たようなインスタンスを大量に扱う」場面で極めて有効。
1. なぜFlyweightが必要か?
❌ 大量のオブジェクトが似たような情報を個別に保持すると、メモリが逼迫する
# 数十万個のツリーオブジェクトに、毎回「種別・色・形状」が含まれている
→ 実質的に同じデータが膨大に複製される
✅ 共通データ(内部状態)は共有オブジェクトに集約し、個別データ(外部状態)のみを保持
tree_type = TreeType("oak", "green", "texture.png")
tree = Tree(x, y, tree_type)
→ 内部状態の共有により、インスタンス数を抑えてメモリ効率を最適化
2. 基本構造
✅ Flyweight(共有される内部状態)
class TreeType:
def __init__(self, name, color, texture):
self.name = name
self.color = color
self.texture = texture
def draw(self, x, y):
print(f"{self.name} を {x},{y} に描画(色: {self.color} / テクスチャ: {self.texture})")
✅ Flyweight Factory(共有インスタンスの管理)
class TreeFactory:
_tree_types = {}
@classmethod
def get_tree_type(cls, name, color, texture):
key = (name, color, texture)
if key not in cls._tree_types:
cls._tree_types[key] = TreeType(name, color, texture)
return cls._tree_types[key]
✅ コンテキスト(外部状態)
class Tree:
def __init__(self, x, y, tree_type: TreeType):
self.x = x
self.y = y
self.tree_type = tree_type
def draw(self):
self.tree_type.draw(self.x, self.y)
✅ 使用例
forest = []
for i in range(10000):
tree_type = TreeFactory.get_tree_type("oak", "green", "oak_texture.png")
forest.append(Tree(i, i, tree_type))
# 表示例
forest[0].draw()
forest[-1].draw()
出力:
oak を 0,0 に描画(色: green / テクスチャ: oak_texture.png)
oak を 9999,9999 に描画(色: green / テクスチャ: oak_texture.png)
3. Python的応用:functools.lru_cache
を使った共有インスタンス管理
from functools import lru_cache
@lru_cache(maxsize=None)
def get_icon(name, size):
print(f"{name} サイズ{size}のアイコンをロード")
return f"{name}_{size}_icon"
# 使用
icon1 = get_icon("save", 32)
icon2 = get_icon("save", 32) # キャッシュヒット
→ 共通リソースの読み込み最適化としてもFlyweight的に使える
4. 実務ユースケース
✅ UIコンポーネントのスキン/アイコン共有
→ 同じアイコンを複数ボタンで使い回すことで軽量化
✅ 地図アプリのランドマークアイコン
→ 数千のマーカーに対して、共通のアイコンデータを共有
✅ ゲームにおけるエフェクト・弾・敵ユニットの粒子構造
→ プロトタイプ・タイプ情報を共有してパフォーマンス改善
✅ Webアプリケーションのキャッシュ済みテンプレート構造
→ テンプレートエンジンがHTMLパーツを再利用
5. よくある誤用と対策
❌ 外部状態まで共有してしまい、正しい描画や動作が崩れる
→ ✅ 外部状態(位置・IDなど)は個別オブジェクトで必ず管理する
❌ 共有オブジェクトの構築コストを軽視して都度生成
→ ✅ Flyweight Factoryを介してキャッシュと制御を徹底する
❌ 状態の変更が共有インスタンスに波及して副作用を引き起こす
→ ✅ Flyweightは原則イミュータブル設計とする
結語
Flyweightパターンとは、“重複を構造化し、メモリを共有知で最適化する設計”である。
- 内部状態を集約・共有し、必要最小限のインスタンス数で効率的な構造を実現
- 速度・メモリ・スケーラビリティの観点から、高負荷アプリにおける最適解
- PythonではFactory・キャッシュ・構造分離により、明確で安全な共有ロジックが構築可能
Pythonicとは、“個を分け、共を活かすこと”。
Flyweightパターンはその最小性の知性を、設計の経済性として導き出す技法である。