享元模式(Flyweight Pattern)
定义
“享元模式(Flyweight Pattern)是池技术的重要实现方式,其定义如下:Use sharing to support large numbers of fine-grained objects efficiently.(使用共享对象可有效地支持大量的细粒度的对象。)”Excerpt From: 秦小波 著. “设计模式之禅(第2版)(华章原创精品).” iBooks.“如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时就应该考虑使用;还有就是对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式” Excerpt From: 程杰. “大话设计模式.” iBooks.
使用共享对象,共享对象的处理是享元模式的关键,把哪些内容作为共享对象,以及对象如何存储在哪儿,怎么存储的问题。
理解享元模式的应用场景,为了减少内存的使用,将对象元素固定的部分提出来,通过hashmap的方式存储,不会为每个对象实例创建这个信息,而是所有实例共享这个数据。
参考Java的UML图示如下:
@startuml
FlyweightFactory *--> Flyweight
Flyweight <|-- ConcreteFlyweight
Flyweight <|-- UnsharedConcreteFlyweight
Client --> FlyweightFactory
Client --> UnsharedConcreteFlyweight
Client --> ConcreteFlyweight
@enduml
代码实现
看似复杂的java UML模型,其实用python来实现还是比较简单的,就是利用python class的类变量,将共享的信息存储在类变量中,通过向类变量的pool中添加key value,来共享这些数据,定义接口从pool中获取数据即可。
'''
享元模式的应用举例,假设我们在游戏开发过程中,需要创建一片森林,而森林中有不同的树种,树种的类型就那么几种,是固定的,而其他的比如位置,树龄是不同的
此时共享的部分各种树种类就可以被提出来作为共享的类变量
'''
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) # 从对象池中获取对象,如果没有填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):
'''
一直没理解享元模式这个render的作用是什么,其实render函数表示的是一种操作。举个例子:
连接数据库,pool表示的是与数据库的连接池,而render表示的是各种数据库交互的动作get、commit等等,此时,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)
t4.render(rnd.randint(age_min, age_max),
rnd.randint(min_point, max_point),
rnd.randint(min_point, max_point))
t5 = Tree(TreeType.cherry_tree)
t5.render(rnd.randint(age_min, age_max),
rnd.randint(min_point, max_point),
rnd.randint(min_point, max_point))
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()
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。