sugar/ 九月 27, 2019/ python设计模式/ 0 comments

一个享元(Flyweight)就是一个包含状态独立的不可变(又称固有的)数据的共享对象。依赖状态的可变(又称非固有的)数据不应是享元的一部分,因为每个对象的这种信息都不同,无法共享。如果享元需要非固有的数据,应该由客户端代码显式地提供。

享元模式是一个用于优化的设计模式。

实现:

# coding: utf-8

import random
from enum import Enum

TreeType = Enum('TreeType', 'apple_tree cherry_tree peach_tree')


class Tree:
    pool = dict()

    def __new__(cls, tree_type):
        obj = cls.pool.get(tree_type, None)
        if not obj:
            obj = object.__new__(cls)
            cls.pool[tree_type] = obj
            obj.tree_type = tree_type
        return obj

    def render(self, age, x, y):
        print('render a tree of type {} and age {} at ({}, {})'.format(self.tree_type, age, x, y))


def main():
    rnd = random.Random()
    age_min, age_max = 1, 30    # 单位为年
    min_point, max_point = 0, 100
    tree_counter = 0

    for _ in range(10):
        t1 = Tree(TreeType.apple_tree)
        t1.render(rnd.randint(age_min, age_max),
                  rnd.randint(min_point, max_point),
                  rnd.randint(min_point, max_point))
        tree_counter += 1

    for _ in range(3):
        t2 = Tree(TreeType.cherry_tree)
        t2.render(rnd.randint(age_min, age_max),
                  rnd.randint(min_point, max_point),
                  rnd.randint(min_point, max_point))
        tree_counter += 1

    for _ in range(5):
        t3 = Tree(TreeType.peach_tree)
        t3.render(rnd.randint(age_min, age_max),
                  rnd.randint(min_point, max_point),
                  rnd.randint(min_point, max_point))
        tree_counter += 1

    print('trees rendered: {}'.format(tree_counter))
    print('trees actually created: {}'.format(len(Tree.pool)))

    t4 = Tree(TreeType.cherry_tree)
    t5 = Tree(TreeType.cherry_tree)
    t6 = Tree(TreeType.apple_tree)
    print('{} == {}? {}'.format(id(t4), id(t5), id(t4) == id(t5)))
    print('{} == {}? {}'.format(id(t5), id(t6), id(t5) == id(t6)))

if __name__ == '__main__':
    main()

在我们想要优化内存使用提高应用性能之时,可以使用享元。在所有内存受限(想一想嵌入式系统)或关注性能的系统(比如图形软件和电子游戏)中,这一点相当重要。

一般来说,在应用需要创建大量的计算代价大但共享许多属性的对象时,可以使用享元。重点在于将不可变(可共享)的属性与可变的属性区分开。我们实现了一个树渲染器,支持三种不同的树家族。通过显式地向render()方法提供可变的年龄和x, y属性,我们成功地仅创建了3个不同的对象,而不是18个。虽然那看起来似乎没什么了不起,但是想象一下,如果是2000棵树而不是18棵树,那又会怎样呢?

Share this Post

说点什么

avatar
  Subscribe  
提醒