設計模式的定義:為了解決面向對象系統中重要和重復的設計封裝在一起的一種代碼實現框架,可以使得代碼更加易於擴展和調用
四個基本要素:模式名稱,問題,解決方案,效果
六大原則:
1.開閉原則:一個軟件實體,如類,模塊和函數應該對擴展開放,對修改封閉。既軟件實體應盡量在不修改原有代碼的情況下進行擴展。
2.里氏替換原則:所有引用父類的方法必須能透明的使用其子類的對象
3.依賴倒置原則:高層模塊不應該依賴底層模塊,二者都應該依賴其抽象,抽象不應該依賴於細節,細節應該依賴抽象,換而言之,要針對接口編程而不是針對實現編程
4.接口隔離原則:使用多個專門的接口,而不是使用單一的總接口,即客戶端不應該依賴那些並不需要的接口
5.迪米特法則:一個軟件實體應該盡可能的少與其他實體相互作用
6.單一直責原則:不要存在多個導致類變更的原因.即一個類只負責一項職責
零:接口
定義:一種特殊的類,聲明了若干方法,要求繼承該接口的類必須實現這種方法
作用:限制繼承接口的類的方法的名稱及調用方式,隱藏了類的內部實現
from abc import ABCMeta,abstractmethod class Payment(metaclass=ABCMeta): @abstractmethod#定義抽象方法的關鍵字 def pay(self,money): pass # @abstractmethod # def pay(self,money): # raise NotImplementedError class AiliPay(Payment): #子類繼承接口,必須實現接口中定義的抽象方法,否則不能實例化對象 def pay(self,money): print('使用支付寶支付%s元'%money) class ApplePay(Payment): def pay(self,money): print('使用蘋果支付支付%s元'%money)
一:單例模式
定義:保證一個類只有一個實例,並提供一個訪問它的全局訪問點
適用場景:當一個類只能有一個實例而客戶可以從一個眾所周知的訪問點訪問它時
優點:對唯一實例的受控訪問,相當於全局變量,但是又可以防止此變量被篡改
class Singleton(object): #如果該類已經有了一個實例則直接返回,否則創建一個全局唯一的實例 def __new__(cls, *args, **kwargs): if not hasattr(cls,'_instance'): cls._instance = super(Singleton,cls).__new__(cls) return cls._instance class MyClass(Singleton): def __init__(self,name): if name: self.name = name a = MyClass('a') print(a) print(a.name) b = MyClass('b') print(b) print(b.name) print(a) print(a.name)
二:簡單工廠模式
定義:不直接向客戶暴露對象創建的實現細節,而是通過一個工廠類來負責創建產品類的實例
角色:工廠角色,抽象產品角色,具體產品角色
優點:隱藏了對象創建代碼的細節,客戶端不需要修改代碼
缺點:違反了單一職責原則,將創建邏輯集中到一個工廠里面,當要添加新產品時,違背了開閉原則
from abc import ABCMeta,abstractmethod class Payment(metaclass=ABCMeta): #抽象產品角色 @abstractmethod def pay(self,money): pass class AiliPay(Payment): #具體產品角色 def __init__(self,enable_yuebao=False): self.enable_yuebao = enable_yuebao def pay(self,money): if self.enable_yuebao: print('使用余額寶支付%s元'%money) else: print('使用支付寶支付%s元'%money) class ApplePay(Payment): # 具體產品角色 def pay(self,money): print('使用蘋果支付支付%s元'%money) class PaymentFactory: #工廠角色 def create_payment(self,method): if method == 'alipay': return AiliPay() elif method == 'yuebao': return AiliPay(True) elif method == 'applepay': return ApplePay() else: return NameError p = PaymentFactory() f = p.create_payment('yuebao') f.pay(100)
三:工廠方法模式
定義:定義一個創建對象的接口(工廠接口),讓子類決定實例化哪個接口
角色:抽象工廠角色,具體工廠角色,抽象產品角色,具體產品角色
適用場景:需要生產多種,大量復雜對象的時候,需要降低代碼耦合度的時候,當系統中的產品類經常需要擴展的時候
優點:每個具體的產品都對應一個具體工廠,不需要修改工廠類的代碼,工廠類可以不知道它所創建的具體的類,隱藏了對象創建的實現細節
缺點:每增加一個具體的產品類,就必須增加一個相應的工廠類
#!/usr/bin/env python # -*- coding: utf-8 -*- # __author__= 'luhj' from abc import ABCMeta,abstractmethod class Payment(metaclass=ABCMeta): #抽象產品 @abstractmethod def pay(self,money): pass class AliPay(Payment): #具體產品 def pay(self,money): print('使用支付寶支付%s元'%money) class ApplePay(Payment): def pay(self,money): print('使用蘋果支付支付%s元'%money) class PaymentFactory(metaclass=ABCMeta): #抽象工廠 @abstractmethod def create_payment(self): pass class AliPayFactory(PaymentFactory): #具體工廠 def create_payment(self): return AliPay() class ApplePayFactory(PaymentFactory): def create_payment(self): return ApplePay() af = AliPayFactory() ali = af.create_payment() ali.pay(100) #如果要新增支付方式 class WechatPay(Payment): def pay(self,money): print('使用微信支付%s元'%money) class WechatPayFactory(PaymentFactory): def create_payment(self): return WechatPay() w = WechatPayFactory() wc = w.create_payment() wc.pay(200)
四:抽象工廠模式
定義:定義一個工廠類接口,讓工廠子類來創建一系列相關或相互依賴的對象
角色:抽象工廠角色,具體工廠角色,抽象產品角色,具體產品角色,客戶端
適用場景:系統要獨立於產品的創建和組合時,強調一系列相關產品的對象設計以便進行聯合調試時,提供一個產品類庫,想隱藏產品的具體實現時
優點:將客戶端與類的具體實現相分離,每個工廠創建了一個完整的產品系列,易於交換產品.有利於產品的一致性
缺點:難以支持新種類的產品
from abc import abstractmethod, ABCMeta # ------抽象產品------ class PhoneShell(metaclass=ABCMeta): @abstractmethod def show_shell(self): pass class CPU(metaclass=ABCMeta): @abstractmethod def show_cpu(self): pass class OS(metaclass=ABCMeta): @abstractmethod def show_os(self): pass # ------抽象工廠------ class PhoneFactory(metaclass=ABCMeta): @abstractmethod def make_shell(self): pass @abstractmethod def make_cpu(self): pass @abstractmethod def make_os(self): pass # ------具體產品------ class SmallShell(PhoneShell): def show_shell(self): print('小手機殼') class BigShell(PhoneShell): def show_shell(self): print('大手機殼') class AppleShell(PhoneShell): def show_shell(self): print('蘋果機殼') class SnapDragonCPU(CPU): def show_cpu(self): print('驍龍CPU') class MediaTekCPU(CPU): def show_cpu(self): print('聯發科CPU') class AppleCPU(CPU): def show_cpu(self): print('蘋果CPU') class Andriod(OS): def show_os(self): print('安卓系統') class IOS(OS): def show_os(self): print('iOS系統') # ------具體工廠------ class MiFactory(PhoneFactory): def make_shell(self): return BigShell() def make_os(self): return Andriod() def make_cpu(self): return SnapDragonCPU() class HuaweiFactory(PhoneFactory): def make_shell(self): return SmallShell() def make_os(self): return Andriod() def make_cpu(self): return MediaTekCPU() class AppleFactory(PhoneFactory): def make_shell(self): return AppleShell() def make_os(self): return IOS() def make_cpu(self): return AppleCPU() # ------客戶端------ class Phone: def __init__(self,shell,os,cpu): self.shell=shell self.os=os self.cpu=cpu def show_info(self): print('手機信息') self.cpu.show_cpu() self.shell.show_shell() self.os.show_os() def make_phone(factory): cpu = factory.make_cpu() os = factory.make_os() shell = factory.make_shell() return Phone(shell,os,cpu) p1 = make_phone(AppleFactory()) p1.show_info()
五:建造者模式
定義:將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示
角色:抽象建造者,具體建造者,指揮者,產品
適用場景:當創建復雜對象的算法應該獨立於對象的組成部分以及它的裝配方式,當構造過程允許被構造的對象有不同的表示
優點:隱藏了一個產品的內部結構和裝配過程,將構造代碼與表示代碼分開,可以對構造過程進行更精確的控制
from abc import abstractmethod, ABCMeta #------產品------ class Player: def __init__(self,face=None, body=None, arm=None, leg=None): self.face =face self.body=body self.arm=arm self.leg=leg def __str__(self): return '%s,%s,%s,%s'%(self.face,self.body,self.arm,self.leg) #------建造者------ class PlayerBuilder(metaclass=ABCMeta): @abstractmethod def build_face(self): pass @abstractmethod def build_body(self): pass @abstractmethod def build_arm(self): pass @abstractmethod def build_leg(self): pass @abstractmethod def get_player(self): pass #------具體建造者------ class BeautifulWoman(PlayerBuilder): def __init__(self): self.player=Player() def build_face(self): self.player.face = '白臉蛋' def build_body(self): self.player.body = '好身材' def build_arm(self): self.player.arm = '細胳膊' def build_leg(self): self.player.leg = '大長腿' def get_player(self): return self.player #------指揮者------ class PlayerDirecter: def build_player(self,builder): builder.build_face() builder.build_body() builder.build_arm() builder.build_leg() return builder.get_player() director = PlayerDirecter() builder = BeautifulWoman() p = director.build_player(builder) print(p)
六:適配器模式
定義:將一個接口轉換為客戶希望的另一個接口,該模式使得原本由於接口不兼容而不能一起工作的那些類可以一起工作
角色:目標接口,待適配的類,適配器
適用場景:想使一個已經存在的類,但其接口不符合你的要求.想對一些已經存在的子類.不可能每一個都是用子類來進行適配,對象適配器可以適配其父類接口

from abc import abstractmethod, ABCMeta class Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): raise NotImplementedError class Alipay(Payment): def pay(self, money): print("支付寶支付%s元"%money) class ApplePay(Payment): def pay(self, money): print("蘋果支付%s元"%money) #------待適配的類----- class WeChatPay: def fuqian(self,money): print('微信支付%s元'%money) #------類適配器------ class RealWeChatPay(Payment,WeChatPay): def pay(self, money): return self.fuqian(money) #-----對象適配器----- class PayAdapter(Payment): def __init__(self,payment): self.payment=payment def pay(self, money): return self.payment.fuqian(money) #RealWeChatPay().pay(100) p=PayAdapter(WeChatPay()) p.pay(200)
七:組合模式
定義:將對象組合成樹形結構以表示'部分-整體'的層次結構.組合模式使得用戶對單個對象和組合對象的使用具有一致性
角色:抽象組件,葉子組件,復合組件,客戶端
適用場景:表示對象的'部分-整體'層次結構,希望用戶忽略組合對象與單個對象的不同,用戶統一使用組合結構中的所有對象
優點:定義了包含基本對象和組合對象的類層次結構,簡化客戶端代碼,即客戶端可以一致的使用組合對象和單個對象,更容易新增新類型的組件
缺點:很難限制組合中的組件
from abc import abstractmethod, ABCMeta #-------抽象組件-------- class Graph(metaclass=ABCMeta): @abstractmethod def draw(self): pass @abstractmethod def add(self,graph): pass def get_children(self): pass #---------葉子組件-------- class Point(Graph): def __init__(self,x,y): self.x = x self.y = y def draw(self): print(self) def add(self,graph): raise TypeError def get_children(self): raise TypeError def __str__(self): return '點(%s,%s)'%(self.x,self.y) class Line(Graph): def __init__(self,p1,p2): self.p1 = p1 self.p2 = p2 def draw(self): print(self) def add(self,graph): raise TypeError def get_children(self): raise TypeError def __str__(self): return '線段(%s,%s)'%(self.p1,self.p2) #--------復合組件--------- class Picture(Graph): def __init__(self): self.children = [] def add(self,graph): self.children.append(graph) def get_children(self): return self.children def draw(self): print('-----復合圖形-----') for g in self.children: g.draw() print('結束') #---------客戶端--------- pic1 = Picture() point = Point(2,3) pic1.add(point) pic1.add(Line(Point(1,2),Point(4,5))) pic1.add(Line(Point(0,1),Point(2,1))) pic2 = Picture() pic2.add(Point(-2,-1)) pic2.add(Line(Point(0,0),Point(1,1))) pic = Picture() pic.add(pic1) pic.add(pic2) pic.draw()
八:代理模式
定義:為其他對象提供一種代理以控制對特定對象的訪問
角色:抽象實體,實體,代理
適用場景:遠程代理(為遠程的對象提供代理),虛代理(根據需要創建很大的對象,即懶加載),保護代理(控制對原始對象的訪問,用於具有不同訪問權限的對象)
優點:遠程代理(可以隱藏對象位於遠程地址空間的事實),虛代理(可對大對象的加載進行優化),保護代理(允許在訪問一個對象時有一些附加的處理邏輯,例如權限控制)
from abc import ABCMeta, abstractmethod #抽象實體 class Subject(metaclass=ABCMeta): @abstractmethod def get_content(self): pass #實體 class RealSubject(Subject): def __init__(self,filename): print('讀取文件%s內容'%filename) f = open(filename) self.content = f.read() f.close() def get_content(self): return self.content #遠程代理 class ProxyA(Subject): def __init__(self,filename): self.subj =RealSubject(filename) def get_content(self): return self.subj.get_content() #虛代理 class ProxyB(Subject): def __init__(self,filename): self.filename = filename self.subj = None def get_content(self): if not self.subj: self.subj = RealSubject(self.filename) return self.subj.get_content() #保護代理 class ProxyC(Subject): def __init__(self,filename): self.subj = RealSubject(filename) def get_content(self): return '???' #客戶端 filename = 'abc.txt' username = input('>>') if username!='alex': p=ProxyC(filename) else: p=ProxyB(filename) print(p.get_content())
九:觀察者模式
定義:定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴它的對象都會得到通知並被自動更新.觀察者模式又稱為'發布訂閱'模式
角色:抽象主題,具體主題(發布者),抽象觀察者,具體觀察者(訂閱者)
適用場景:當一個抽象模型有兩個方面,其中一個方面依賴於另一個方面.將兩者封裝在獨立的對象中以使它們各自獨立的改變和復用
當一個對象的改變需要同時改變其他對象,而且不知道具體有多少對象以待改變
當一個對象必須通知其他對象,而又不知道其他對象是誰,即這些對象之間是解耦的
優點:目標和觀察者之間的耦合最小,支持廣播通信
缺點:多個觀察者之間互不知道對方的存在,因此一個觀察者對主題的修改可能造成錯誤的更新
from abc import ABCMeta, abstractmethod #抽象主題 class Oberserver(metaclass=ABCMeta): @abstractmethod def update(self): pass #具體主題 class Notice: def __init__(self): self.observers = [] def attach(self,obs): self.observers.append(obs) def detach(self,obs): self.observers.remove(obs) def notify(self): for obj in self.observers: obj.update(self) #抽象觀察者 class ManagerNotice(Notice): def __init__(self,company_info=None): super().__init__() self.__company_info = company_info @property def company_info(self): return self.__company_info @company_info.setter def company_info(self,info): self.__company_info = info self.notify() #具體觀察者 class Manager(Oberserver): def __init__(self): self.company_info = None def update(self,noti): self.company_info = noti.company_info #消息訂閱-發送 notice = ManagerNotice() alex=Manager() tony=Manager() notice.attach(alex) notice.attach(tony) notice.company_info="公司運行良好" print(alex.company_info) print(tony.company_info) notice.company_info="公司將要上市" print(alex.company_info) print(tony.company_info) notice.detach(tony) notice.company_info="公司要破產了,趕快跑路" print(alex.company_info) print(tony.company_info)
十:策略模式
定義:定義一系列的算法把它們一個個封裝起來,並且使它們可相互替換.該模式使得算法可獨立於使用它的客戶而變化
角色:抽象策略,具體策略,上下文
適用場景:許多相關的類僅僅是行為有異,需使用一個算法的不同變體,算法使用了客戶端無需知道的數據,一個類中的多個行為以多個條件語句存在可以將其封裝在不同的策略類中
優點:定義了一系列可重用的算法和行為,消除了一些條件語句,可提供相同行為的不同實現
缺點:客戶必須了解不同的策略,策略與上下文之間的通信開銷,增加了對象的數目
from abc import ABCMeta, abstractmethod import random #抽象策略 class Sort(metaclass=ABCMeta): @abstractmethod def sort(self,data): pass #具體策略 class QuickSort(Sort): def quick_sort(self,data,left,right): if left<right: mid = self.partation(data,left,right) self.quick_sort(data,left,mid-1) self.quick_sort(data,mid+1,right) def partation(self,data,left,right): tmp = data[left] while left < right: while left<right and data[right]>=tmp: right -= 1 data[left] = data[right] while left<right and data[left]<=tmp: left += 1 data[right] = data[left] data[left] = tmp return left def sort(self,data): print("快速排序") return self.quick_sort(data,0,len(data)-1) class MergeSort(Sort): def merge(self,data,low,mid,high): i = low j = mid+1 ltmp = [] while i <= mid and j <= high: if data[i] <= data[j]: ltmp.append(data[i]) i+=1 else: ltmp.append(data[j]) j+=1 while i <= mid: ltmp.append(data[i]) i+=1 while j <= high: ltmp.append(data[j]) j+=1 data[low:high+1]=ltmp def merge_sort(self,data,low,high): if low<high: mid = (low+high)//2 self.merge_sort(data,low,mid) self.merge_sort(data,mid+1,high) self.merge(data,low,mid,high) def sort(self,data): print("歸並排序") return self.merge_sort(data,0,len(data)-1) #上下文 class Context: def __init__(self,data,strategy=None): self.data=data self.strategy=strategy def set_strategy(self,strategy): self.strategy=strategy def do_strategy(self): if self.strategy: self.strategy.sort(self.data) else: raise TypeError li = list(range(100000)) random.shuffle(li) context = Context(li,MergeSort()) context.do_strategy() random.shuffle(context.data) context.set_strategy(QuickSort()) context.do_strategy()
十一:責任鏈模式
定義:使多個對象有機會處理請求,從而避免請求的發布者和接收者之間的耦合關系,將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象能處理它為止
角色:抽象處理者,具體處理者,客戶端
適用場景:有多個對象可以處理一個請求,哪個對象處理由運行時決定
優點:降低耦合度,一個對象無需知道是其他哪一個對象處理其請求
缺點:請求不保證被接收,鏈的末端沒有處理或鏈配置錯誤
from abc import ABCMeta, abstractmethod class Handler(metaclass=ABCMeta): @abstractmethod def handel_leave(self,day): pass class GeneralManagerHandler(Handler): def handel_leave(self,day): if day < 10: print('總經理批准請假%s天'%day) else: print('不能請假') class DepartmentManagerHandler(Handler): def __init__(self): self.successor = GeneralManagerHandler() def handel_leave(self,day): if day < 7: print('部門經理批准請假%s天' % day) else: print('部門經理無權批假') self.successor.handel_leave(day) class ProjectDirectorHandler(Handler): def __init__(self): self.successor = DepartmentManagerHandler() def handel_leave(self,day): if day < 3: print('項目經理批准請假%s天' % day) else: print('項目經理無權批假') self.successor.handel_leave(day) day = 6 h = ProjectDirectorHandler() h.handel_leave(day)
from abc import ABCMeta, abstractmethod #--模仿js事件處理 class Handler(metaclass=ABCMeta): @abstractmethod def add_event(self,func): pass @abstractmethod def handler(self): pass class BodyHandler(Handler): def __init__(self): self.func = None def add_event(self,func): self.func = func def handler(self): if self.func: return self.func() else: print('已經是最后一級,無法處理') class ElementHandler(Handler): def __init__(self,successor): self.func = None self.successor = successor def add_event(self,func): self.func = func def handler(self): if self.func: return self.func() else: return self.successor.handler() #客戶端 body = {'type': 'body', 'name': 'body', 'children': [], 'father': None} div = {'type': 'div', 'name': 'div', 'children': [], 'father': body} a = {'type': 'a', 'name': 'a', 'children': [], 'father': div} body['children'] = div div['children'] = a body['event_handler'] = BodyHandler() div['event_handler'] = ElementHandler(div['father']['event_handler']) a['event_handler'] = ElementHandler(a['father']['event_handler']) def attach_event(element,func): element['event_handler'].add_event(func) #測試 def func_div(): print("這是給div的函數") def func_a(): print("這是給a的函數") def func_body(): print("這是給body的函數") attach_event(div,func_div) #attach_event(a,func_a) attach_event(body,func_body) a['event_handler'].handler()
十二:迭代器模式
定義:提供一種方法可順序訪問一個聚合對象中的各個元素,而又不需要暴露該對象的內部指示
適用場景:實現方法__iter__,__next__
class LinkedList: class Node: def __init__(self,item=None): self.item=item self.next=None class LinkedListIterator: def __init__(self,node): self.node = node #實現next方法,返回下一個元素 def __next__(self): if self.node: cur_node = self.node self.node = cur_node.next return cur_node.item def __iter__(self): return self def __init__(self,iterable=None): self.head = LinkedList.Node(0) self.tail = self.head self.extend(iterable) #鏈表尾部追加元素 def append(self,obj): s = LinkedList.Node(obj) self.tail.next = s self.tail = s #鏈表自動增加長度 def extend(self,iterable): for obj in iterable: self.append(obj) self.head.item += len(iterable) def __iter__(self): return self.LinkedListIterator(self.head.next) def __len__(self): return self.head.item def __str__(self): return '<<'+', '.join(map(str,self)) + '>>' li = [i for i in range(100)] lk = LinkedList(li) print(lk)
十三:模板方法模式
定義:定義一個操作中算法的骨架,將一些步驟延遲到子類中,模板方法使得子類可以不改變一個算法的結構即可重定義該算法某些特定的步驟
角色:抽象類(定義抽象的原子操作,實現一個模板方法作為算法的骨架),具體類(實現原子操作)
適用場景:一次性實現一個算法不變的部分,各個子類的公共行為,應該被提取出來集中到公共的父類中以避免代碼重復,控制子類擴展
from abc import ABCMeta, abstractmethod #----抽象類----- class IOHandler(metaclass=ABCMeta): @abstractmethod def open(self,name): pass @abstractmethod def deal(self,change): pass @abstractmethod def close(self): pass #在父類中定義了子類的行為 def process(self,name,change): self.open(name) self.deal(change) self.close() #子類中只需要實現部分算法,而不需要實現所有的邏輯 #-----具體類-------- class FileHandler(IOHandler): def open(self,name): self.file = open(name,'w') def deal(self,change): self.file.write(change) def close(self): self.file.close() f = FileHandler() f.process('abc.txt','hello')
