來(lái)源:《設(shè)計(jì)模式 可復(fù)用面向?qū)ο筌浖幕A(chǔ)》 ---GoF
結(jié)構(gòu)型模式
1. 適配器
- 起源
有一個(gè)已經(jīng)存在的類(lèi),你想使用它,但是它又不符合你的接口規(guī)范,所以你需要將其轉(zhuǎn)換成你想要的接口形式。
- 方法
有兩種實(shí)現(xiàn)方法,一種是繼承,一種是組合。
對(duì)于C++這樣的強(qiáng)類(lèi)型語(yǔ)言來(lái)說(shuō),繼承需要使用多重繼承,因?yàn)槟惚匦枥^承原始類(lèi)以及要適配的接口,而對(duì)于python這種就只需要繼承原始類(lèi)即可。
一般而言,組合會(huì)比繼承更靈活,而且多重繼承也容易踩坑,所以建議用組合形式。
- 代碼
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)換器一個(gè)思想。
2. 橋接
- 起源
如果需要設(shè)計(jì)一個(gè)功能,在windows和linux平臺(tái)下都能運(yùn)行,同時(shí)還需要支持?jǐn)U展新平臺(tái),擴(kuò)展新功能,合理的做法是:將實(shí)現(xiàn)部分和抽象部分分離,抽象部分定義各個(gè)平臺(tái)的基本操作,實(shí)現(xiàn)部分使用抽象接口實(shí)現(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
### 實(shí)現(xiàn)部分
class ApplicationWindow(Window):
def draw_contents(self):
self._imp.device_text()
class IconWindow(Window):
def draw_contents(self):
self._imp.device_bitmap()
- 思想
這里的主要思想就是將一個(gè)功能的不同部分剝離開(kāi),能夠各自獨(dú)立的擴(kuò)展。
3. 組合
- 起源
對(duì)于又有組件又有組件聚合成的容器的系統(tǒng),如果用戶(hù)希望容器和組件一樣對(duì)待,那么可以為他們提供一個(gè)統(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
- 思想
通過(guò)統(tǒng)一接口,降低系統(tǒng)中的類(lèi)型數(shù)量。
裝飾
- 起源
如果希望動(dòng)態(tài)的給對(duì)象增加一些職責(zé),裝飾會(huì)比生成子類(lèi)更加靈活一點(diǎn)。
- 代碼
class VisualComponent(object):
def draw():
pass
class TextView(VisualComponent):
"""被裝飾的類(lèi)"""
pass
class Decorator(VisualComponent):
"""裝飾類(lèi)的基類(lèi)"""
def __init__(self, component):
self._component = component
def draw(self):
self._component.draw()
class BorderDecorator(Decorator):
"""裝飾類(lèi)"""
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)類(lèi)似,但裝飾不會(huì)該表對(duì)象的職責(zé)。
- 裝飾可以視為僅有一個(gè)組合的組合,但它的目的不在于對(duì)象聚合。
- 裝飾并沒(méi)有改變這個(gè)對(duì)象本身,而策略會(huì)改變對(duì)象的內(nèi)核。
外觀
- 起源
為了提高復(fù)用度,一般子系統(tǒng)或者組件只會(huì)提供最基礎(chǔ)的功能,而使用者大部分情況下不會(huì)關(guān)心這些基礎(chǔ)組件,為了降低復(fù)雜度,會(huì)給使用者提供一個(gè)更高層次的易用的對(duì)外接口。
享元
- 起源
系統(tǒng)中存在大量相同的細(xì)粒度對(duì)象,可以使用共享技術(shù)有效的降低系統(tǒng)中的對(duì)象數(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):
"""被共享的對(duì)象"""
def __init__(self, char):
self._charcode = char
def draw(self, window, context):
"""這里傳入外部狀態(tài)"""
pass
- 思想
運(yùn)用享元模式需要區(qū)分對(duì)象的內(nèi)部狀態(tài)與外部狀態(tài),外部狀態(tài)可以在運(yùn)行時(shí)作為參數(shù)傳遞。
- 注意
可以用享元模式來(lái)實(shí)現(xiàn)狀態(tài)模式和策略模式。
代理
- 起源
控制對(duì)對(duì)象的訪(fǎng)問(wèn),有遠(yuǎn)程代理,虛代理,保護(hù)代理等。
- 代碼
class Image(object):
def __init__(self, filename):
pass
def draw(self):
pass
class ImageProxy(object):
"""保護(hù)代理,惰性加載對(duì)象"""
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)和適配器模式以及裝飾模式很像,但他們的目的是不一樣的,適配器是為了提供不一樣的接口,裝飾模式是為了提供額外的功能,代理模式是為了控制對(duì)對(duì)象的訪(fǎng)問(wèn)。