0
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(フライウェイト)パターンは、
多数の類似オブジェクトを生成する際に、共通部分を共有(キャッシュ)することでメモリ消費を抑える設計パターンである。

再利用可能な軽量インスタンス(Flyweight)を管理することで、オブジェクト生成のコストを最小限に抑える


1. なぜFlyweightが必要か?

❌ 同じ内容のインスタンスを大量に作成するとメモリが無駄に消費される

for _ in range(1000000):
    users.append(User(role="guest"))

本質的に同一のデータが、重複して無駄なオブジェクトを持つ


✅ 共通部分を共有し、個別状態のみを外部に持たせる

role = FlyweightFactory.get("guest")
User(role=role, id=1234)

共通状態(intrinsic)と固有状態(extrinsic)を分離して効率化


2. 基本構造

✅ Flyweight(共有されるオブジェクト)

class Role:
    def __init__(self, name, permissions):
        self.name = name
        self.permissions = permissions

✅ FlyweightFactory(インスタンスの再利用を管理)

class RoleFactory:
    _roles = {}

    @classmethod
    def get(cls, name):
        if name not in cls._roles:
            if name == "guest":
                cls._roles[name] = Role("guest", ["read"])
            elif name == "admin":
                cls._roles[name] = Role("admin", ["read", "write", "delete"])
            else:
                cls._roles[name] = Role(name, [])
        return cls._roles[name]

✅ Context(固有状態を外部で保持)

class User:
    def __init__(self, user_id, role: Role):
        self.user_id = user_id  # extrinsic state
        self.role = role        # intrinsic state

    def describe(self):
        print(f"User {self.user_id} has role {self.role.name} with permissions {self.role.permissions}")

✅ 使用例

guest_role = RoleFactory.get("guest")

users = [User(user_id=i, role=guest_role) for i in range(3)]

for u in users:
    u.describe()

出力:

User 0 has role guest with permissions ['read']
User 1 has role guest with permissions ['read']
User 2 has role guest with permissions ['read']

3. Python的応用:文字列インターンや小数値キャッシュにも応用されている

a = "hello"
b = "hello"
print(a is b)  # True(同一オブジェクト)

x = 256
y = 256
print(x is y)  # True(小整数のキャッシュ)

Python自体が小さな値・文字列を内部でFlyweight的に管理している


4. 実務ユースケース

✅ ゲーム開発でのオブジェクト共有(草木、弾丸、敵タイプ)

同じ見た目・動作を持つオブジェクトのインスタンスを共有


✅ フォント・グラフィック・アイコンのレンダリング最適化

→ 表示内容が同じものを都度生成せずに共有


✅ ドキュメントエディタにおける文字スタイル管理

→ 同じフォント設定の文字を再利用してメモリ節約


✅ Webアプリのセッションやキャッシュ構造における軽量化

同じレスポンス・設定を共有して高速化


5. よくある誤用と対策

❌ 全てをFlyweightにして逆に管理が複雑に

→ ✅ 共有する価値のある “不変で再利用可能な状態” のみに適用


❌ 固有状態までFlyweightに含めてしまう

→ ✅ 固有状態(ユーザーIDなど)は外に出し、構造を分離する


❌ スレッドセーフでない共有状態の利用

→ ✅ ファクトリに同期制御を導入する or イミュータブルに設計


結語

Flyweightパターンとは、“共通の知識をひとつにまとめ、軽量かつ大量に広げる設計”である。

  • オブジェクトの重複を排除し、再利用可能な構造体として共有
  • 固有と共通の状態を明確に分離し、メモリ効率と可読性を両立
  • Pythonでは文字列や小数値のような構造に自然と内在している

Pythonicとは、“同じものは一つだけに、異なるものは分けて持つ”。
Flyweightパターンはその知性を、設計の密度として洗練する技法である。

0
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
0
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?