享元模式
由于对象创建的开销,面向对象的系统可能还面临性能问题,性能问题通常在资源受限的嵌入式系统中出现,比如智能手机和平板电脑。大型复杂系统中也可能会出现同样问题,因为要在其中创建大量对象,这些对象需要同时并存。
eg:如果一个3D地带的每个对象都是单独创建,未使用数据共享,那么性能将是无法接受的。
享元模式通过为相似对象引入数据共享来最小化内存使用,提升性能
一个享元就是一个包含状态独立的不可变数据的共享对象;
依赖状态改的可变数据不应该是享元的一部分,因为每个对象的这种信息不同,无法共享;如果享元需要非固有的数据,应该有客户端代码显式的提供
例子: FPS游戏:士兵->拥有相同的状态(看起来一样,跑,跳) 不同的状态(枪支,健康状况,地理位置)
若想要享元模式有效,需满足的条件
- 应用需要大量的对象
- 对象太多,存储/渲染他们的代价带大。一旦移除对象中的可变状态(因为在需要之时,应该有客户端代码显式地传递给享元),多组不同的对象可被更少的共享对象替代。
- 对象ID对应用不重要。对象共享会造成ID比较失败,所以不能依赖对象ID(那些在客户端代码看来不同的对象,最终具有相同的ID)
以下是在一个场景展示18棵树,但是实际上我们只创建了3棵树而已
# 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()