第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