來源:《設計模式 可復用面向?qū)ο筌浖幕A》 ---GoF
結(jié)構(gòu)型模式
1. 適配器
- 起源
有一個已經(jīng)存在的類径筏,你想使用它葛假,但是它又不符合你的接口規(guī)范,所以你需要將其轉(zhuǎn)換成你想要的接口形式滋恬。
- 方法
有兩種實現(xiàn)方法聊训,一種是繼承,一種是組合恢氯。
對于C++這樣的強類型語言來說带斑,繼承需要使用多重繼承,因為你必需繼承原始類以及要適配的接口勋拟,而對于python這種就只需要繼承原始類即可勋磕。
一般而言,組合會比繼承更靈活敢靡,而且多重繼承也容易踩坑挂滓,所以建議用組合形式。
- 代碼
class Adaptee(object):
def a_useful_function(self):
pass
class InheritAdapter(Adaptee):
"""繼承形式"""
def interface_function(self):
self.a_useful_function()
class CombineAdapter(object):
"""組合形式"""
def __init__(self, adaptee):
self._adaptee = adaptee
def interface_function(self):
self._adaptee.a_useful_function()
- 思想
跟插頭轉(zhuǎn)換器一個思想啸胧。
2. 橋接
- 起源
如果需要設計一個功能赶站,在windows和linux平臺下都能運行,同時還需要支持擴展新平臺纺念,擴展新功能亲怠,合理的做法是:將實現(xiàn)部分和抽象部分分離,抽象部分定義各個平臺的基本操作柠辞,實現(xiàn)部分使用抽象接口實現(xiàn)不同的功能团秽。
- 代碼
class Window(object):
def __init__(self, imp):
self._imp = imp
def draw_contents(self):
pass
### 抽象部分
class WindowImp(object):
def device_text(self):
pass
def device_bitmap(self):
pass
class XWindowImp(WindowImp):
def device_text(self):
pass
def device_bitmap(self):
pass
### 實現(xiàn)部分
class ApplicationWindow(Window):
def draw_contents(self):
self._imp.device_text()
class IconWindow(Window):
def draw_contents(self):
self._imp.device_bitmap()
- 思想
這里的主要思想就是將一個功能的不同部分剝離開,能夠各自獨立的擴展。
3. 組合
- 起源
對于又有組件又有組件聚合成的容器的系統(tǒng)习勤,如果用戶希望容器和組件一樣對待踪栋,那么可以為他們提供一個統(tǒng)一的抽象接口。
- 代碼
class Equipment(object):
def add(self):
pass
def net_price(self):
return 0
class FloppyDisk(Equipment):
"""組件"""
def net_price(self):
return 1
class CompositeEquipment(Equipment):
"""容器"""
def __init__(self):
self._equipment = []
def add(self, eq):
self._equipment.append(eq)
def net_price(self):
total = 0
for eq in self._equipment:
total += eq.net_price()
return total
- 思想
通過統(tǒng)一接口图毕,降低系統(tǒng)中的類型數(shù)量夷都。
裝飾
- 起源
如果希望動態(tài)的給對象增加一些職責,裝飾會比生成子類更加靈活一點予颤。
- 代碼
class VisualComponent(object):
def draw():
pass
class TextView(VisualComponent):
"""被裝飾的類"""
pass
class Decorator(VisualComponent):
"""裝飾類的基類"""
def __init__(self, component):
self._component = component
def draw(self):
self._component.draw()
class BorderDecorator(Decorator):
"""裝飾類"""
def __init__(self, component):
self._component = component
def draw(self):
super(BorderDecorator, self).draw()
self.draw_border()
def draw_border(self):
pass
- 注意
- 與適配器結(jié)構(gòu)類似囤官,但裝飾不會該表對象的職責。
- 裝飾可以視為僅有一個組合的組合蛤虐,但它的目的不在于對象聚合党饮。
- 裝飾并沒有改變這個對象本身,而策略會改變對象的內(nèi)核驳庭。
外觀
- 起源
為了提高復用度刑顺,一般子系統(tǒng)或者組件只會提供最基礎的功能,而使用者大部分情況下不會關心這些基礎組件饲常,為了降低復雜度蹲堂,會給使用者提供一個更高層次的易用的對外接口。
享元
- 起源
系統(tǒng)中存在大量相同的細粒度對象贝淤,可以使用共享技術有效的降低系統(tǒng)中的對象數(shù)量柒竞。
- 代碼
class GlyphFactory(object):
def __init__(self):
self._character = {}
def create_character(self, char):
c = self._character.get(char)
if c is None:
self._character[char] = c = Character(char)
return c
class Character(object):
"""被共享的對象"""
def __init__(self, char):
self._charcode = char
def draw(self, window, context):
"""這里傳入外部狀態(tài)"""
pass
- 思想
運用享元模式需要區(qū)分對象的內(nèi)部狀態(tài)與外部狀態(tài),外部狀態(tài)可以在運行時作為參數(shù)傳遞播聪。
- 注意
可以用享元模式來實現(xiàn)狀態(tài)模式和策略模式能犯。
代理
- 起源
控制對對象的訪問,有遠程代理犬耻,虛代理,保護代理等执泰。
- 代碼
class Image(object):
def __init__(self, filename):
pass
def draw(self):
pass
class ImageProxy(object):
"""保護代理枕磁,惰性加載對象"""
def __init__(self, filename):
self._filename = filename
self._image = None
def get_image(self):
if not self._image:
self._image = Image(self._filename)
return self._image
def draw(self):
self.get_image().draw()
- 注意
代理模式的結(jié)構(gòu)和適配器模式以及裝飾模式很像,但他們的目的是不一樣的术吝,適配器是為了提供不一樣的接口计济,裝飾模式是為了提供額外的功能,代理模式是為了控制對對象的訪問排苍。