Python設計模式-結構型:適配器模式,裝飾者模式,代理模式,組合模式,外觀模式 適配器模式定義及簡單實現案例 裝飾者模式定義及簡單實現案例 代理模式定義及簡單實現案例 組合模式定義及簡單實現案例 外觀模式定義及簡單實現案例 適配器模式 adapter 電子產品的電源插頭插在轉換插頭上,然後轉換插 ...
Python設計模式-結構型:適配器模式,裝飾者模式,代理模式,組合模式,外觀模式
- 適配器模式定義及簡單實現案例
- 裝飾者模式定義及簡單實現案例
- 代理模式定義及簡單實現案例
- 組合模式定義及簡單實現案例
- 外觀模式定義及簡單實現案例
適配器模式 adapter
電子產品的電源插頭插在轉換插頭上,然後轉換插頭插上電源,電子產品就能正常工作了。這就是適配器模式
# -*- coding: utf-8 -*-
class OldCourse(object):
"""
老的課程類
"""
def show(self):
"""
顯示關於本課程的所有信息
"""
print("show description")
print("show teacher of course")
print("show labs")
class Page(object):
"""
使用課程對象的客戶端
"""
def __init__(self, course):
self.course = course
def render(self):
self.course.show()
class NewCourse(object):
"""
新的課程類, 為了模塊化顯示課程信息,實現了新的課程類
"""
def show_desc(self):
"""
顯示描述信息
"""
print("show description")
def show_teacher(self):
"""
顯示老師信息
"""
print("show teacher of course")
def show_labs(self):
"""
顯示實驗
"""
print("show labs")
class Adapter(object):
"""
適配器, 儘管實現了新的課程類,但是在很多代碼中還是需要使用 OldCourse.show() 方法
"""
def __init__(self, course):
self.course = course
def show(self):
"""
適配方法,調用真正的操作
"""
self.course.show_desc()
self.course.show_teacher()
self.course.show_labs()
if __name__ == '__main__':
old_course = OldCourse()
page = Page(old_course)
page.render()
print("")
new_course = NewCourse()
# 新課程類沒有 show 方法,我們需要使用適配器進行適配
adapter = Adapter(new_course)
page = Page(adapter)
page.render()
適配器模式就是把一個類的介面變換成客戶端所期待的另一種介面,使原本因介面不相容而無法在一起工作的兩個類能夠在一起工作。
裝飾者模式 Decorator
裝飾者模式能動態的給對象添加行為。如果你對 Flask 比較熟悉的話,應該知道在使用 Flask-Login 的時候可以使用 login_required 裝飾器包裝一個需要用戶登錄訪問的view
# -*- coding: utf-8 -*-
from functools import wraps
HOST_DOCKER = 0
def docker_host_required(f):
"""
裝飾器,必須要求 host 類型是 HOST_DOCKER
"""
@wraps(f)
def wrapper(*args, **kwargs):
if args[0].type != HOST_DOCKER:
raise Exception("Not docker host")
else:
return f(*args, **kwargs)
return wrapper
class Host(object):
"""
host 類
"""
def __init__(self, type):
self.type = type
# 裝飾這一方法
@docker_host_required
def create_container(self):
print("create container")
if __name__ == '__main__':
# 初始化 Host
host = Host(HOST_DOCKER)
host.create_container()
print("")
# 再次初始化 Host
host = Host(1)
host.create_container()
在上面的代碼中,Host有一個方法Host.create_container,只有當Host實例的類型是DOCKER_HOST的時候才能執行該方法。為了加上這一行為,我們使用了裝飾者模式。可以看出使用裝飾者模式,我們可以動態改變類的行為,同時能提高代碼復用性,因為任何類型為HOST_DOCKER的Host都可以使用該裝飾器。另外要說明下:為了更好的實現裝飾器,我們使用functools.wrap函數。
代理模式 proxy
所謂代理模式就是給一個對象提供一個代理,並由代理對象控制對原對象的訪問。通過代理,我們可以對訪問做一些控制。在開髮網站的過程中,針對一些頻繁訪問的資源,我們會使用緩存。
# -*- coding: utf-8 -*-
from time import sleep
class Redis(object):
"""
用於模擬 redis 服務
"""
def __init__(self):
"""
使用字典存儲數據
"""
self.cache = dict()
def get(self, key):
"""
獲取數據
"""
return self.cache.get(key)
def set(self, key, value):
"""
設置數據
"""
self.cache[key] = value
class Image(object):
"""
圖片對象,圖片存在七牛雲存儲中,我們只保存了一個地址
"""
def __init__(self, name):
self.name = name
@property
def url(self):
sleep(2)
return "https://dn-syl-static.qbox.me/img/logo-transparent.png"
class Page(object):
"""
用於顯示圖片
"""
def __init__(self, image):
"""
需要圖片進行初始化
"""
self.image = image
def render(self):
"""
顯示圖片
"""
print(self.image.url)
redis = Redis()
class ImageProxy(object):
"""
圖片代理,首次訪問會從真正的圖片對象中獲取地址,以後都從 Redis 緩存中獲取
"""
def __init__(self, image):
self.image = image
@property
def url(self):
addr = redis.get(self.image.name)
if not addr:
addr = self.image.url
print("Set url in redis cache!")
redis.set(self.image.name, addr)
else:
print("Get url from redis cache!")
return addr
if __name__ == '__main__':
img = Image(name="logo")
proxy = ImageProxy(img)
page = Page(proxy)
# 首次訪問
page.render()
print("")
# 第二次訪問
page.render()
代理對象和真實的對象之間都實現了共同的介面,這使我們可以在不改變原介面情況下,使用真實對象的地方都可以使用代理對象。其次,代理對象在客戶端和真實對象之間直接起到了中介作用,同時通過代理對象,我們可以在將客戶請求傳遞給真實對象之前做一些必要的預處理。
組合模式 composite
什麼是組合模式?按照定義來說,組合模式是將對象組合成樹形結構表示,使得客戶端對單個對象和組合對象的使用具有一致性。組合模式的使用通常會生成一棵對象樹,對象樹中的葉子結點代表單個對象,其他節點代表組合對象。調用某一組合對象的方法,其實會迭代調用所有其葉子對象的方法。
使用組合模式的經典例子是 Linux 系統內的樹形菜單和文件系統。在樹形菜單中,每一項菜單可能是一個組合對象,其包含了菜單項和子菜單,這樣就形成了一棵對象樹。在文件系統中,葉子對象就是文件,而文件夾就是組合對象,文件夾可以包含文件夾和文件,同樣又形成了一棵對象樹。同樣的例子還有員工和領導之間的關係
# -*- coding: utf-8 -*-
import abc
class Worker(object):
"""
員工抽象類
"""
__metaclass__ = abc.ABCMeta
def __init__(self, name):
self.name = name
@abc.abstractmethod
def work(self):
pass
class Employe(Worker):
"""
員工類
"""
__metaclass__ = abc.ABCMeta
def work(self):
print("Employ: %s start to work " % self.name)
class Leader(Worker):
"""
領導類
"""
def __init__(self, name):
self.members = []
super(Leader, self).__init__(name)
def add_member(self, employe):
if employe not in self.members:
self.members.append(employe)
def remove_member(self, employe):
if employe in self.members:
self.members.remove(employe)
def work(self):
print("Leader: %s start to work" % self.name)
for employe in self.members:
employe.work()
if __name__ == '__main__':
employe_1 = Employe("employe_1")
employe_2 = Employe("employe_2")
leader_1 = Leader("leader_1")
leader_1.add_member(employe_1)
leader_1.add_member(employe_2)
employe_3 = Employe("employe_3")
leader_2 = Leader("leader_2")
leader_2.add_member(employe_3)
leader_2.add_member(leader_1)
leader_2.work()
外觀模式 facade
所謂外觀模式,就是將各種子系統的複雜操作通過外觀模式簡化,讓客戶端使用起來更方便簡潔。
- 比如你夏天晚上出門時,要關閉電燈,關閉電視機,關閉空調,如果有了一個總開關,通過它可以關閉電燈,電視機和空調,你出門的時候關閉總開關就行了。
- 在這個例子中,你就是客戶端,總開關就是外觀模式的化身
# -*- coding: utf-8 -*-
class User(object):
"""
用戶類
"""
def is_login(self):
return True
def has_privilege(self, privilege):
return True
class Course(object):
"""
課程類
"""
def can_be_learned(self):
return True
class Lab(object):
"""
實驗類
"""
def can_be_started(self):
return True
class Client(object):
"""
客戶類,用於開始一個實驗
"""
def __init__(self, user, course, lab):
self.user = user
self.course = course
self.lab = lab
def start_lab(self):
"""
開始實驗,需要一系列的判斷:用戶是否登錄,課程是否可以學習,實驗是否可以開始。判斷非常繁瑣!
"""
if self.user.is_login() and self.course.can_be_learned() and self.lab.can_be_started():
print("start lab")
else:
print("can not start lab")
class FacadeLab(object):
"""
新的Lab類,應用了面向對象模式
"""
def __init__(self, user, course, lab):
self.user = user
self.course = course
self.lab = lab
def can_be_started(self):
if self.user.is_login() and self.course.can_be_learned() and self.lab.can_be_started():
return True
else:
return False
class NewClient(object):
"""
新的客戶類,使用外觀模式
"""
def __init__(self, facade_lab):
self.lab = facade_lab
def start_lab(self):
"""
開始實驗,只需要判斷 FacadeLab 是否可以開始
"""
if self.lab.can_be_started:
print("start lab")
else:
print("can not start lab")
if __name__ == '__main__':
user = User()
course = Course()
lab = Lab()
client = Client(user, course, lab)
client.start_lab()
print("Use Facade Pattern:")
facade_lab = FacadeLab(user, course, lab)
facade_client = NewClient(facade_lab)
facade_client.start_lab()
外觀模式的主要目的在於降低系統的複雜程度,在面向對象軟體系統中,類與類之間的關係越多,不能表示系統設計得越好,反而表示系統中類之間的耦合度太大,這樣的系統在維護和修改時都缺乏靈活性,因為一個類的改動會導致多個類發生變化,而外觀模式的引入在很大程度上降低了類與類之間的耦合關係。引入外觀模式之後,增加新的子系統或者移除子系統都非常方便,客戶類無須進行修改(或者極少的修改),只需要在外觀類中增加或移除對子系統的引用即可。
本文來自博客園,作者:OCEANEYES.GZY,轉載請註明原文鏈接:https://www.cnblogs.com/oceaneyes-gzy/p/16462979.html