1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで実装するFlyweightパターン:軽量オブジェクトによるメモリ最適化

Posted at

概要

Flyweight(フライウェイト)パターンは、
多数生成されるオブジェクトのうち、共通部分を共有することでメモリ消費を抑えるための設計パターンである。

特に、同じ構造・状態を持つオブジェクトが大量に存在する状況において、
内部状態の共有によって冗長なインスタンス生成を防ぎ、効率的なシステム構築を可能にする


1. なぜFlyweightが必要か?

❌ 同じ情報を持つ大量のオブジェクトを毎回生成すると、メモリ圧迫につながる

char1 = Character("A", "Arial", 12)
char2 = Character("A", "Arial", 12)
char3 = Character("A", "Arial", 12)

→ 実体は同一なのに全て別オブジェクトがメモリを消費


✅ Flyweightで共通部分を共有し、インスタンス数を削減

factory = CharacterFactory()
char1 = factory.get("A", "Arial", 12)
char2 = factory.get("A", "Arial", 12)

同じプロパティを持つオブジェクトは再利用される


2. 基本構造

✅ Flyweightクラス(共有される構造)

class Character:
    def __init__(self, char, font, size):
        self.char = char
        self.font = font
        self.size = size

    def render(self, position):
        print(f"Rendering '{self.char}' at {position} with {self.font} ({self.size}px)")

✅ Flyweight Factory(インスタンス共有管理)

class CharacterFactory:
    def __init__(self):
        self._pool = {}

    def get(self, char, font, size):
        key = (char, font, size)
        if key not in self._pool:
            self._pool[key] = Character(char, font, size)
        return self._pool[key]

    def count(self):
        return len(self._pool)

✅ 使用例

factory = CharacterFactory()
positions = [(0,0), (1,0), (2,0), (3,0)]

for pos in positions:
    c = factory.get("A", "Arial", 12)
    c.render(pos)

print(f"生成されたインスタンス数: {factory.count()}")

出力:

Rendering 'A' at (0, 0) with Arial (12px)
Rendering 'A' at (1, 0) with Arial (12px)
Rendering 'A' at (2, 0) with Arial (12px)
Rendering 'A' at (3, 0) with Arial (12px)
生成されたインスタンス数: 1

3. Python的応用:functools.lru_cache による自動共有

from functools import lru_cache

@lru_cache(maxsize=128)
def create_char(char, font, size):
    return Character(char, font, size)

c1 = create_char("A", "Arial", 12)
c2 = create_char("A", "Arial", 12)

print(c1 is c2)  # True

Pythonの標準機能で簡易Flyweightが実現可能


4. 実務ユースケース

✅ フォントレンダリングエンジン(PDF/ゲーム/エディタ)

→ 同じフォント・サイズ・文字を何度も描画する場面で有効


✅ 地図・座標系でのアイコン表示

→ 同一マーカー、アイコンなどを共有インスタンスで管理


✅ Webアプリのキャッシュ済み構成部品の使い回し

→ UI部品やレスポンステンプレートをインスタンス化せずに使い回す


✅ ゲーム開発での背景・敵・エフェクトパターンの共通化

オブジェクトの描画・振る舞いの再利用と最適化


5. よくある誤用と対策

❌ 状態をすべて内部に持たせてしまい、インスタンスごとの違いが出せない

→ ✅ 共有できる状態(内部)と固有状態(外部)を明確に分離する


❌ Factoryが肥大化し、責務が曖昧になる

→ ✅ 取得・生成・破棄の責任を明確に分離して設計する


❌ Flyweightを適用すべきでない状況に導入しすぎる

→ ✅ 「大量に重複するオブジェクト」が前提であることを再確認する


結語

Flyweightパターンとは、“繰り返される構造を賢く共有し、軽量な設計を実現する技法”である。

  • 重複構造を共有することで、インスタンス生成コストを最小化
  • 内部状態と外部状態を分離することで、柔軟な管理と再利用を両立
  • Pythonでは dictlru_cache により、直感的かつ軽量に設計可能

Pythonicとは、“冗長さを排し、必要なだけを扱うこと”。
Flyweightパターンはその軽量性と再利用性を、構造の共有という形で表現する技法である。

1
1
0

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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?