源码地址:https://github.com/weilanhanf/PythonDesignPatterns
说明:
如果一个软件系统在运行时所创建的相同或相似对象数量太多,将导致运行代价过高,带来系统资源浪费、性能下降等问题 如何避免系统中出现大量相同或相似的对象,同时又不影响客户端程序通过面向对象的方式对这些对象进行操作呢。例如在文字编辑软件中,把每个字符当成对象处理,并分配相应的系统空间,但是随着字符串数量的增加将会逐渐耗尽系统资源,有大量细粒度的对象充斥在系统之中,导致系统运行效率低下。解决上述问题就可以使用享元模式——通过共享机制来解决系统资源消耗问题。
享元模式:运用共享技术有效地支持大量细粒度对象的复用。
内部状态(Intrinsic State):存储在享元对象内部并且不会随环境改变而改变的状态,内部状态可以共享(例如:字符的内容)
外部状态(Extrinsic State):随环境改变而改变的、不可以共享的状态。享元对象的外部状态通常由客户端保存,并在享元对象被创建之后,需要使用的时候再传入到享元对象内部。一个外部状态与另一个外部状态之间是相互独立的(例如:字符的颜色和大小)
享元池(Flyweight Pool):存储共享实例对象的地方
原理
(1) 将具有相同内部状态的对象存储在享元池中,享元池中的对象是可以实现共享的
(2) 需要的时候将对象从享元池中取出,即可实现对象的复用
(3) 通过向取出的对象注入不同的外部状态,可以得到一系列相似的对象,而这些对象在内存中实际上只存储一份
享元模式的结构
享元模式包含以下4个角色: Flyweight(抽象享元类) ConcreteFlyweight(具体享元类) UnsharedConcreteFlyweight(非共享具体享元类) FlyweightFactory(享元工厂类)
实例:
#假设有一个网上咖啡选购平台,客户可以在该平台上下订单订购咖啡,平台会根据用户位置进行线下配送。
# 假设其咖啡对象构造如下:
class Coffee:
name = ''
price =0
def __init__(self,name):
self.name = name
self.price = len(name)#在实际业务中,咖啡价格应该是由配置表进行配置,或者调用接口获取等方式得到,此处为说明享元模式,将咖啡价格定为名称长度,只是一种简化
def show(self):
print("Coffee Name:%s Price:%s"%(self.name,self.price)) """
#对应客户顾客类
class Customer:
name=""
def __init__(self,name):
self.name=name
def order(self,coffee_name):
print("%s ordered a cup of coffee:%s"%(self.name,coffee_name))
return Coffee(coffee_name)
""" """
按照一般的处理流程,用户在网上预订咖啡,其代表用户的Customer类中生成一个Coffee类,直到交易流程结束。整个流程是没有问题的。
但是在高并发的情况下,也就是说单位时间内购买咖啡的用户越来越多,生成的咖啡实例就会越来越多,系统资源消耗越来越大
避免重复实例的出现,是节约系统资源的一个突破口。引入咖啡工厂类
"""
class CoffeeFactory():
coffee_dict = {}
def getCoffee(self, name):
if self.coffee_dict.__contains__(name) == False:
self.coffee_dict[name] = Coffee(name)
return self.coffee_dict[name]
def getCoffeeCount(self):
return len(self.coffee_dict) # 咖啡工厂中,getCoffeeCount直接返回当前实例个数。重写后的Customer
class Customer:
coffee_factory=""
name=""
def __init__(self,name,coffee_factory):
self.name=name
self.coffee_factory=coffee_factory
def order(self,coffee_name):
print("%s ordered a cup of coffee:%s"%(self.name,coffee_name))
return self.coffee_factory.getCoffee(coffee_name) #假设业务中短时间内有多人订了咖啡,业务模拟如下
if __name__=="__main__":
coffee_factory=CoffeeFactory()
customer_1=Customer("A Client",coffee_factory)
customer_2=Customer("B Client",coffee_factory)
customer_3=Customer("C Client",coffee_factory)
c1_capp=customer_1.order("cappuccino")
c1_capp.show()
c2_mocha=customer_2.order("mocha")
c2_mocha.show()
c3_capp=customer_3.order("cappuccino")
c3_capp.show()
print("Num of Coffee Instance:%s"%coffee_factory.getCoffeeCount())
打印结果:
A Client ordered a cup of coffee:cappuccino
Coffee Name:cappuccino Price:10
B Client ordered a cup of coffee:mocha
Coffee Name:mocha Price:5
C Client ordered a cup of coffee:cappuccino
Coffee Name:cappuccino Price:10
Num of Coffee Instance:2
模式优点
可以减少内存中对象的数量,使得相同或者相似的对象在内存中只保存一份,从而可以节约系统资源,提高系统性能 外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享
模式缺点
使得系统变得复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化 为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长
模式适用环境
一个系统有大量相同或者相似的对象,造成内存的大量耗费 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中 在使用享元模式时需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源,因此,在需要多次重复使用享元对象时才值得使用享元模式
参考链接:
https://yq.aliyun.com/articles/70529?spm=a2c4e.11155435.0.0.723038da7MwIMk