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
關于作者
?? 讀書城南,?? 在未來面前,我們都是孩子~
- ?? 一個熱衷于探索學習新方向、新事物的智能產品經理,閑暇時間喜歡coding??、畫圖??、音樂??、學習ing~
?? Social Media
??? Blog: http://oceaneyes.top
? PM導航: https://pmhub.oceangzy.top
?? CNBLOG: https://www.cnblogs.com/oceaneyes-gzy/
?? AI PRJ自己部署的一些演算法demo: http://ai.oceangzy.top/
?? Email: [email protected]
?? WeChat: OCEANGZY
- ?? 公眾號: UncleJoker-GZY
?? 感謝打賞~


轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/498972.html
標籤:面向對象
