第26章:享元模式
享元模式
享元(flyweight)模式:运用共享技术有效地支持大量细粒度的对象。
Flyweight
类:所有具体享元类的超类或接口,通过这个接口,Flyweight
可以接受并作用于外部状态。
ConcreteFlyweight
:继承Flyweight
超类或实现Flyweight
接口,并为内部状态增加存储空间。
UnsharedConcreteFlyweight
是指那些不需要共享的Flyweight
子类。因为Flyweight
接口共享成为可能,但它并不强制共享。
FlyweightFactory
是一个享元工厂,用来创建并管理Flyweight
对象。它主要是用来确保合理地共享Flyweight
,当用户请求一个Flyweight
时,FlyweightFactory
对象提供一个已创建的实例或者创建一个(如果不存在的话)。
客户端代码
结果表示
内部状态与外部状态
享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,有时就能够受大幅度地减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目。
享元模式应用
-
如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时应该考虑使用享元模式;
-
对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。
使用享元模式,通过共享对象,极大减少实例总数。如果共享的对象越多,存储节约也就越多,节约量随着共享状态的增多而增大。
例,.NET
中字符串string
运用了Flyweight
模式:
返回值是True
,这两个字符串是相同的实例
享元模式更多的时候是一种底层的设计模式,但现实中也是有应用的。比如说休闲游戏开发中,像围棋、五子棋、跳棋等,它们都有大量的棋子对象,棋子的内部状态应该是颜色,而外部状态应该是棋子的方位坐标。
享元模式示例
任务:多客户网站
from abc import ABCMeta, abstractmethod
from typing import Text
class User(object):
"""
用户类
"""
def __init__(self, name: Text) -> None:
self.__name = name
@property
def name(self) -> Text:
return self.__name
class WebSite(metaclass=ABCMeta):
"""
网站抽象类
"""
@abstractmethod
def use(self, user: User) -> None:
pass
string1 = "网站抽象类"
string2 = "网站抽象类"
string1 == string2
True
class ConcreteWebSite(WebSite):
"""
具体网站类
"""
def __init__(self, name: Text) -> None:
self.__name = name
def use(self, user: User) -> None:
print("网站分类:" + self.__name, "用户:" + user.name)
class WebSiteFactory(object):
"""
网站工厂类
"""
def __init__(self):
self.__flyweights = {}
def get_web_site_category(self, key: Text) -> WebSite:
if not self.__flyweights.get(key):
self.__flyweights[key] = ConcreteWebSite(key)
return self.__flyweights[key]
def get_web_site_count(self) -> int:
return len(self.__flyweights)
# 客户端代码
if __name__ == "__main__":
f = WebSiteFactory()
fx = f.get_web_site_category("产品展示")
fx.use(User("小菜"))
fy = f.get_web_site_category("产品展示")
fy.use(User("大鸟"))
fz = f.get_web_site_category("产品展示")
fz.use(User("娇娇"))
fl = f.get_web_site_category("博客")
fl.use(User("老顽童"))
fm = f.get_web_site_category("博客")
fm.use(User("桃谷六仙"))
fn = f.get_web_site_category("博客")
fn.use(User("南海鳄神"))
print("得到网站分类总数为%d" % f.get_web_site_count())
网站分类:产品展示 用户:小菜
网站分类:产品展示 用户:大鸟
网站分类:产品展示 用户:娇娇
网站分类:博客 用户:老顽童
网站分类:博客 用户:桃谷六仙
网站分类:博客 用户:南海鳄神
得到网站分类总数为2