日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python设计模式总结

發布時間:2025/3/17 python 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python设计模式总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

介紹

每一個模式描述了一個在我們周圍不斷重復發生的問題,以及該問題的解決方案的核心。這樣你就能一次又一次地使用該方案而不必做重復勞動。—— Christopher Alexander

軟件危機催生了設計模式,面向對象,軟件工程。

是什么

每一個設計模式系統地命名、解釋和評價了面向對象系統中一個重要的和重復出現的設計。

熱身

既然是針對面向對象的,讓我們先來回顧一下面向的三大特性和接口

面向對象的三大特性:封裝,繼承和多態

封裝

把數據和函數包裝在類里,類的邊界限制外界的訪問,將類內和類外隔絕開,并視情況提供一些接口。

尤其是一些關鍵的變量(比如在類內部計算出來的變量),建議設置為私有變量,隔絕類外的訪問和修改。

class A:def __init__(self, name):self.__name = namedef getname(self): # 接口return self.__namedef setname(self, name): # 接口self.__name = nameclass B(A):def __init__(self):print(self.__name)b = B() # 報錯

私有變量只有類內才能訪問,類外不能,親兒子也不可以!

這里,我們讓B繼承A,實例化,得到以下出錯信息。這是因為私有變量在定義階段就會發生變形,原理復習這里

AttributeError: ‘B’ object has no attribute ‘_B__name’

繼承和多態

繼承是為了實現代碼復用,并且子類可以重寫父類的方法或者派生自己的屬性。Python語言本身就是多態的,程序員不需要關心。

接口:

接口是一種特殊的類,聲明了若干方法,要求繼承該接口的類必須實現這些方法。

作用:限制繼承接口的類的方法的名稱及調用方式;隱藏了類的內部實現。

python中實現接口有兩種方式:抽象類和 raise NotImplemented

# 方式一:父類中定義方法,應用raise NotImplemented約束 class BaseClient(object):def __init__(self):self.api = settings.APIdef execute(self):raise NotImplemented("子類必須實現execute方法")class AgentClient(BaseClient): #子類必須實現raise NotImplemented約束的方法def execute(self):obj = Plugin()res = obj.execute_plugin()self.post_data(res)# 方式二:抽象類 from abc import abstractmethod, ABCMetaclass Payment(metaclass=ABCMeta):@abstractmethoddef pay(self, money):"""支付方法,參數money"""pass#實現Payment接口 class Alipay(Payment):def pay(self, money):print("支付寶支付%s元"%money)class ApplePay(Payment):def pay(self, money):print("蘋果支付%s元"%money)

設計模式六大原則

開閉原則

一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。即軟件實體應盡量在不修改原有代碼的情況下進行擴展。

里氏(Liskov)替換原則

所有引用基類(父類)的地方必須能透明地使用其子類的對象。

# 如果我在下面的高層代碼def func中引用了基類User的對象,那么我一定也可以傳入User子類VIPUser的對象,不論子類是繼承還是重寫了父類中的方法。 class User:def check(self):print('checking')return Trueclass VIPUser(User):def check(self):print('vip-chating')return Truedef chat(self):print('Chatting')def func(user):res = user.check()

依賴倒置原則

高層模塊不應該依賴低層模塊,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。換言之,要針對接口編程,而不是針對實現編程(需求提出后,先定義接口,作為約束,以后不管底層實現如何變,也不會影響到高層)。

接口隔離原則

使用多個專門的接口,而不使用單一的總接口,即客戶端不應該依賴那些它不需要的接口。

class Animal(metaclass=ABCMeta):@abstractmethoddef walk(self):pass@abstractmethoddef swim(self):pass@abstractmethoddef fly(self):passclass Tiger(Animal):def walk(self):print("Tiger Walk")def swim(self):print("Tiger Walk")def fly(self):print("Tiger Walk")

以上肯定不合理,老虎會飛嗎?因此fly這個方法Tiger類根不不需要,但是接口卻約束子類必須實現。正確的應該是定義三個動物類,讓子類進行多繼承:

class LandAnimal(metaclass=ABCMeta):@abstractmethoddef walk(self):passclass SkyAnimal(metaclass=ABCMeta):@abstractmethoddef fly(self):passclass WaterAnimal(metaclass=ABCMeta):@abstractmethoddef swim(self):passclass Tiger(LandAnimal):def walk(self):print("Tiger Walk")class Frog(WaterAnimal, LandAnimal):def walk(self):print('Frog Walk')def swim(self):print('Frog swim')

迪米特法則

一個軟件實體應當盡可能少地與其他實體發生相互作用,也就是解耦。

單一職責原則

不要存在多于一個導致類變更的原因。通俗的說,即一個類只負責一項職責。

設計模式分類

創建型模式

簡單工廠模式

內容

不直接向客戶端暴露對象創建的實現細節,而是通過一個工廠類來負責創建產品類的實例。工廠類屬于底層代碼,客戶端指的是高層代碼。

角色

  • 工廠角色(Creator),隱藏對象創建的細節
  • 抽象產品角色(Product),定義接口
  • 具體產品角色(Concrete Product),實現接口,。

優點

  • 隱藏了對象創建的實現細節;
  • 客戶端不需要修改代碼

缺點:

  • 違反了單一職責原則,將創建邏輯集中到一個工廠類里;
  • 當添加新產品時,需要修改工廠類代碼,違反了開閉原則
from abc import abstractmethod, ABCMeta# 抽象產品角色 class Payment(metaclass=ABCMeta):@abstractmethoddef pay(self, money):pass# 具體產品角色 class Alipay(Payment):def __init__(self, enable_yuebao=False):self.enable_yuebao = enable_yuebaodef 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 Alipay()elif method == 'yuebao':return Alipay(enable_yuebao=True)elif method == "applepay":return ApplePay()else:raise NameError(method)# 通過工廠類創建產品類的實例 f = PaymentFactory() p = f.create_payment("yuebao") p.pay(100)

工廠方法模式

內容

定義一個用于創建對象的接口(工廠接口),讓子類決定實例化哪一個產品類。

角色

  • 抽象工廠角色(Creator),定義工廠類接口
  • 具體工廠角色(Concrete Creator),隱藏對象創建細節
  • 抽象產品角色(Product),定義產品接口
  • 具體產品角色(Concrete Product),實現產品接口

特點

工廠方法模式相比簡單工廠模式將每個具體產品都對應了一個具體工廠。

適用場景

  • 需要生產多種、大量復雜對象的時候
  • 需要降低耦合度的時候
  • 當系統中的產品種類需要經常擴展的時候

優點

  • 每個具體產品都對應一個具體工廠類,不需要修改工廠類代碼
  • 隱藏了對象創建的實現細節

缺點

  • 每增加一個具體產品類,就必須增加一個相應的具體工廠類
from abc import abstractmethod, ABCMeta# 抽象產品角色 class Payment(metaclass=ABCMeta):@abstractmethoddef 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):@abstractmethoddef 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(120)

抽象工廠模式

內容

定義一個工廠類接口,讓工廠子類來創建一系列相關或相互依賴的對象。例:生產一部手機,需要手機殼、CPU、操作系統三類對象進行組裝,其中每類對象都有不同的種類。對每個具體工廠,分別生產一部手機所需要的三個對象。

角色

  • 抽象工廠角色(Creator)
  • 具體工廠角色(Concrete Creator)
  • 抽象產品角色(Product)
  • 具體產品角色(Concrete Product)
  • 客戶端(Client)

特點

相比工廠方法模式,抽象工廠模式中的每個具體工廠都生產一套產品。該模式只負責生成,組裝由客戶端負責

使用場景

  • 系統要獨立于產品的創建與組合時
  • 強調一系列相關的產品對象的設計以便進行聯合使用時
  • 提供一個產品類庫,想隱藏產品的具體實現時

優點

  • 將客戶端與類的具體實現相分離
  • 每個工廠創建了一個完整的產品系列,使得易于交換產品系列
  • 有利于產品的一致性(即產品之間的約束關系)

缺點

  • 難以支持新種類的(抽象)產品。比如加一個電池,所有都要大改。
from abc import abstractmethod, ABCMeta# ------抽象產品------class PhoneShell(metaclass=ABCMeta):@abstractmethoddef show_shell(self):passclass CPU(metaclass=ABCMeta):@abstractmethoddef show_cpu(self):passclass OS(metaclass=ABCMeta):@abstractmethoddef show_os(self):pass# ------抽象工廠------class PhoneFactory(metaclass=ABCMeta):@abstractmethoddef make_shell(self):pass@abstractmethoddef make_cpu(self):pass@abstractmethoddef 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 Android(OS):def show_os(self):print("Android系統")class IOS(OS):def show_os(self):print("iOS系統")# ------具體工廠------ # 創建一系列相關或相互依賴的對象,有利于產品一致性,比如Iphone不能用聯發科,Mi不能用IOS class MiFactory(PhoneFactory):def make_cpu(self):return SnapDragonCPU()def make_os(self):return Android()def make_shell(self):return BigShell()class HuaweiFactory(PhoneFactory):def make_cpu(self):return MediaTekCPU()def make_os(self):return Android()def make_shell(self):return SmallShell()class IPhoneFactory(PhoneFactory):def make_cpu(self):return AppleCPU()def make_os(self):return IOS()def make_shell(self):return AppleShell()# ------客戶端------ # 負責具體組裝class Phone:def __init__(self, cpu, os, shell):self.cpu = cpuself.os = osself.shell = shelldef show_info(self):print("手機信息:")self.cpu.show_cpu()self.os.show_os()self.shell.show_shell()def make_phone(factory):cpu = factory.make_cpu()os = factory.make_os()shell = factory.make_shell()return Phone(cpu, os, shell)p1 = make_phone(HuaweiFactory()) p1.show_info()

創建者模式

內容

將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。

角色

  • 抽象建造者(Builder)
  • 具體建造者(Concrete Builder),隱藏內部結構
  • 指揮者(Director),隱藏裝配過程
  • 產品(Product)

特點

建造者模式與抽象工廠模式相似,也用來創建復雜對象。主要區別是建造者模式著重一步步構造一個復雜對象,而抽象工廠模式著重于多個系列的產品對象。

使用場景

  • 當創建復雜對象的算法(Director)應該獨立于該對象的組成部分以及它們的裝配方式(Builder)時
  • 當構造過程允許被構造的對象有不同的表示時(不同Builder)。

優點

  • 隱藏了一個產品的內部結構和裝配過程
  • 將構造代碼與表示代碼分開
  • 可以對構造過程進行更精細的控制
from abc import abstractmethod, ABCMeta#------產品------class Player: # 游戲角色def __init__(self, face=None, body=None, arm=None, leg=None):self.face = faceself.arm = armself.leg = legself.body = bodydef __str__(self):return "%s, %s, %s, %s" % (self.face, self.arm, self.body, self.leg)#------建造者------# 抽象建造者 class PlayerBuilder(metaclass=ABCMeta): # 捏臉@abstractmethoddef build_face(self):pass@abstractmethoddef build_arm(self):pass@abstractmethoddef build_leg(self):pass@abstractmethoddef build_body(self):pass@abstractmethoddef get_player(self):pass# 具體建造者 class BeautifulWomanBuilder(PlayerBuilder):def __init__(self):self.player = Player()def build_face(self):self.player.face = "漂亮臉蛋"def build_arm(self):self.player.arm="細胳膊"def build_body(self):self.player.body="細腰"def build_leg(self):self.player.leg="長腿"def get_player(self):return self.player#------指揮者------class PlayerDirector:def build_player(self, builder):builder.build_body()builder.build_arm()builder.build_leg()builder.build_face()return builder.get_player()director = PlayerDirector() # setp1: 實例化指揮者 builder = BeautifulWomanBuilder() # step2: 實例化建造者 p = director.build_player(builder) # step3: 指揮者指揮建造者創建游戲角色 print(p)

原型模式

暫不討論,略

單例模式

內容

保證一個類只有一個實例,并提供一個訪問它的全局訪問點。

角色

  • 單例(Singleton)

適用場景

  • 當類只能有一個實例而且客戶可以從一個眾所周知的訪問點訪問它時

優點

  • 對唯一實例的受控訪問
  • 單例相當于全局變量,但防止了命名空間被污染

其它

與單例模式功能相似的概念:全局變量、靜態變量(方法)

單例模式的幾種實現方式

方式一:__new__

這里先了解下__new__和__init__的區別:感謝這位同學的整理

class A(object):def __init__(self):print "init"def __new__(cls,*args, **kwargs):print "new %s"%clsreturn object.__new__(cls, *args, **kwargs)A() """ new <class '__main__.A'> init """

幾點說明:

  • 繼承自object的新式類才有`new_“
  • `__new__至少要有一個參數cls,代表要實例化的類,此參數在實例化時由Python解釋器自動提供
  • __new__必須要有返回值,返回實例化出來的實例,這點在自己實現__new__時要特別注意,可以return父類__new__出來的實例,或者直接是object的__new__出來的實例
  • __init__有一個參數self,就是這個__new__返回的實例,__init__在__new__的基礎上可以完成一些其它初始化的動作,__init__不需要返回值
  • 若__new__沒有正確返回當前類cls的實例,那__init__是不會被調用的,即使是父類的實例也不行
  • class A(object):passclass B(A):def __init__(self):print "init"def __new__(cls,*args, **kwargs):print "new %s"%clsreturn object.__new__(A, *args, **kwargs)b=B() print type(b) """ new <class '__main__.B'> <class '__main__.A'> """

    通過__new__實現單例模式:

    class Singleton(object):def __new__(cls, *args, **kwargs):# 如果當前類沒有_instance屬性,那么就調用父類的__new__方法實例化對象,新增_instance屬性并賦值if not hasattr(cls, "_instance"): cls._instance = super(Singleton, cls).__new__(cls)return cls._instanceclass MyClass(Singleton):def __init__(self, name):self.name = namea = MyClass("a") print(a) # <__main__.MyClass object at 0x0000025D076AD3C8> print(a.name) # ab = MyClass('b') print(b) # <__main__.MyClass object at 0x0000025D076AD3C8> print(b.name) # bb.name = 'xxx' print(a) # <__main__.MyClass object at 0x0000025D076AD3C8> print(a.name) # xxx
    方式二:通過裝飾器

    在裝飾器中,我們通過攔截類的__new__實現,判斷該類是否存在于__dict__字典中,如果存在則返回該類的實例,不存在則實例化該類并且存放于__dict__中。

    # 方式一: def singleton(cls, *args, **kw):instances = {}def getinstance():if cls not in instances:instances[cls] = cls(*args, **kw)return instances[cls]return getinstance@singleton class myclass:passclass1 = myclass() class2 = myclass()assert class1 == class2# 方式二:和上面裝飾器思路是一樣的。只是寫到類方法里。 class Foo:_instance = Nonedef __init__(self):pass@classmethoddef get_instance(cls):if cls._instance:return cls._instanceelse:obj = cls()cls._instance = objreturn obj# 創建實例 obj = Foo.get_instance()
    方式三:文件單例模式:
    # step1: 在一個py文件中定義一個單例類并實例化 class Singleton(object):def __init__(self):passdef foo(self):passdef bar(self):passinstance = Singleton()# step2: 在其它文件中導入實例化對象,每次都是操作同一個實例 from Singleton import instanceinstance.foo() instance.bar()

    文件單例模式的特點:

  • 程序一開始的時候就創建了單例類的實例
  • 如果有人不遵守規定使用已經創建好的實例,而是自己創建則無法實現單例。
  • 創建模式小結

    三種工廠模式:

    • 簡單工廠模式:只有一個工廠
    • 工廠方法模式:一個產品一個工廠
    • 抽象工廠模式:一套產品一個工廠

    結構型模式

    適配器模式

    內容

    將一個類的接口轉換成客戶希望的另一個接口。適配器模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。就單來說就是實現接口一致和代碼復用,如果接口不一致,寫一個轉接頭。

    角色

    • 目標接口(Target)
    • 待適配的類(Adaptee)
    • 適配器(Adapter)

    兩種實現方式

    • 類適配器:使用多繼承
    • 對象適配器:使用組合

    適用場景

    • 想使用一個已經存在的類,而它的接口不符合要求
    • (對象適配器)想使用一些已經存在的子類,但不可能對每一個都進行子類化以匹配它們的接口。對象適配器可以適配它的父類接口。
    from abc import abstractmethod, ABCMeta# 目標接口 class Payment(metaclass=ABCMeta):@abstractmethoddef pay(self, money):raise NotImplementedErrorclass Alipay(Payment):def pay(self, money):print("支付寶支付%s元"%money)class ApplePay(Payment):def pay(self, money):print("蘋果支付%s元"%money)#------待適配類------ class WechatPay:def cost(self, money):print("微信支付%s元"%money)#類適配器 class RealWechatPay(WechatPay, Payment):def pay(self, money):return self.cost(money)# 對象適配器 class RealWechatPay2(Payment):def __init__(self):self.payment = WechatPay()def pay(self, money):return self.payment.cost(money)p = RealWechatPay2() p.pay(111)

    注意:

  • 為什么不直接更改源碼呢?因為其他地方可能調用了源碼。
  • 如果差的太遠,可能無法適配。
  • 橋模式

    暫不討論。

    組合模式

    內容

    將對象組合成樹形結構以表示“部分-整體”的層次結構。組合模式使得用戶對單個對象和組合對象的使用具有一致性。其實就是用設計模式的方式來表達樹形結構,一個節點是一個部分,一個子樹是一個整體。

    角色

    • 抽象組件(Component):抽象組件中定義的方法,葉子和復合組件都要實現
    • 葉子組件(Leaf)
    • 復合組件(Composite):非葉子組件
    • 客戶端(Client)

    適用場景

    • 表示對象的“部分-整體”層次結構(特別是結構是遞歸的)
    • 希望用戶忽略組合對象與單個對象的不同,用戶統一地使用組合結構中的所有對象

    優點

    • 定義了包含基本對象和組合對象的類層次結構
    • 簡化客戶端代碼,即客戶端可以一致地使用組合對象和單個對象
    • 更容易增加新類型的組件

    代碼示例

    # coding : utf-8 # create by ztypl on 2017/5/25from abc import abstractmethod, ABCMeta# 抽象組件 class Graphic(metaclass=ABCMeta):@abstractmethoddef draw(self):pass@abstractmethoddef add(self, graphic):passdef getchildren(self):pass# 圖元 # 葉子組件 class Point(Graphic):def __init__(self, x, y):self.x = xself.y = ydef draw(self):print(self)def add(self, graphic):raise TypeErrordef getchildren(self):raise TypeErrordef __str__(self):return "點(%s, %s)" % (self.x, self.y)# 葉子組件 class Line(Graphic):def __init__(self, p1, p2):self.p1 = p1self.p2 = p2def draw(self):print(self)def add(self, graphic):raise TypeErrordef getchildren(self):raise TypeErrordef __str__(self):return "線段[%s, %s]" % (self.p1, self.p2)# 復合組件 class Picture(Graphic):def __init__(self):self.children = []def add(self, graphic):self.children.append(graphic)def getchildren(self):return self.childrendef draw(self):print("------復合圖形------")for g in self.children:g.draw()print("------END------")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() # pic1.draw() # point.draw()

    裝飾模式

    暫不討論。

    外觀模式

    暫不討論。

    享元模式

    暫不討論

    代理模式

    內容

    為其他對象提供一種代理以控制對這個對象的訪問。

    角色

    • 抽象實體(Subject)
    • 實體(RealSubject)
    • 代理(Proxy)

    使用場景

    • 遠程代理:為遠程的對象提供代理。
    • 理虛代理:根據需要創建很大的對象。
    • 保護代理:控制對原始對象的訪問,用于對象有不同訪問權限時

    優點

    • 遠程代理:可以隱藏對象位于遠程地址空間的事實。高層代碼不需要親自訪問遠程的對象,也不需要知道對象在本地還是遠程
    • 虛代理:可以進行優化,例如根據要求創建對象。比如手機滑屏,未顯示區域會提前加載,但是圖像又很耗費內存,因此加載的是圖像代理,當到達某個臨界值,才加載真實圖像。再比如瀏覽器的無圖模式,點擊時才創建圖片。
    • 保護代理:允許在訪問一個對象時有一些附加的內務處理

    示例代碼

    # coding : utf-8 # create by ztypl on 2017/5/26from abc import ABCMeta, abstractmethodclass Subject(metaclass=ABCMeta):@abstractmethoddef get_content(self):passdef set_content(self, content):passclass RealSubject(Subject):def __init__(self, filename):self.filename = filenameprint("讀取%s文件內容"%filename)f = open(filename)self.__content = f.read()f.close()def get_content(self):return self.__contentdef set_content(self, content):f = open(self.filename, 'w')f.write(content)self.__content = contentf.close()# ProxyA 就是給真實對象套了一個馬甲,和使用真實對象沒區別 class ProxyA(Subject):def __init__(self, filename):self.subj = RealSubject(filename)def get_content(self):return self.subj.get_content()def set_content(self, content):return self.subj.set_content(content)# 虛代理:創建時不會立即加載真實對象,而是在調用后才加載(手機的無圖模式就是這個原理) class ProxyB(Subject):def __init__(self, filename):self.filename = filenameself.subj = Nonedef get_content(self):if not self.subj:self.subj = RealSubject(self.filename)return self.subj.get_content()x = ProxyB('abc.txt') #print(x.get_content())# 保護代理:控制對真實對象的修改 class ProxyC(Subject):def __init__(self, filename):self.subj = RealSubject(filename)def get_content(self):self.subj.get_content()def set_content(self, content):raise PermissionError# filename = "abc.txt" # username = input() # if username!="admin": # p = ProxyC(filename) # else: # p = ProxyA(filename) # # print(p.get_content())

    行為型模式

    解釋器模式

    暫不討論。

    責任鏈模式

    內容

    使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。

    角色

    • 抽象處理者(Handler)
    • 具體處理者(ConcreteHandler)
    • 客戶端(Client)

    適用場景

    • 有多個對象可以處理一個請求,哪個對象處理由運行時決定
    • 在不明確接收者的情況下,向多個對象中的一個提交一個請求

    優點

    • 降低耦合度:一個對象無需知道是其他哪一個對象處理其請求

    示例代碼:請假批準

    from abc import ABCMeta, abstractmethodclass Handler(metaclass=ABCMeta):@abstractmethoddef handle_leave(self, day):passclass GeneralManagerHandler(Handler):def handle_leave(self, day):if day < 10:print("總經理批準%d天假"%day)return Trueelse:print("呵呵")return Falseclass DepartmentManagerHandler(Handler):def __init__(self):self.superior = GeneralManagerHandler()def handle_leave(self, day):if day < 7:print("部門經理批準%d天假"%day)return Trueelse:print("部門經理無權準假")return self.superior.handle_leave(day)class ProjectDirectorHandler(Handler):def __init__(self):self.superior = DepartmentManagerHandler()def handle_leave(self, day):if day < 3:print("項目主管批準%d天假"%day)return Trueelse:print("項目主管無權準假")return self.superior.handle_leave(day)# day = 11 # h = ProjectDirectorHandler() # print(h.handle_leave(day))

    示例代碼:Javascript事件浮升機制

    JS事件浮生(冒泡)復習:http://blog.csdn.net/ayhan_huang/article/details/78629885

    在下面這個示例中,DOM節點的父元素就相當與責任鏈的下一級

    class Handler(metaclass=ABCMeta):@abstractmethoddef add_event(self, func):pass@abstractmethoddef handle(self):passclass BodyHandler(Handler):def __init__(self):self.func = Nonedef add_event(self, func):self.func = funcdef handle(self):if self.func:return self.func()else:print("已到最后一級,無法處理")class ElementHandler(Handler):def __init__(self, parent):self.func = Noneself.parent = parentdef add_event(self, func):self.func = funcdef handle(self):if self.func:return self.func()else:return self.parent.handle()# ---------- 客戶端代碼 -------------------# 定義元素并嵌套 <body><div><a> 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'].append(div) div['children'].append(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的事件,a沒有,那么上浮,執行父元素div的事件 a['event_handler'].handle()

    命令模式

    暫不討論。

    迭代器模式

    內容

    提供一種方法順序訪問一個聚合對象中的各個元素,而又不需要暴露該對象的內部表示

    實現方法

    通過__iter__, __next__ 方法,可以實現一個迭代器

    示例

    下面用到了鏈表這種數據結構,鏈表的知識參考這里:http://blog.csdn.net/ayhan_huang/article/details/78526442

    class LinkList:"""鏈表 頭結點保存鏈表的長度"""class Node:# 節點def __init__(self, item=None):self.item = itemself.next = Noneclass LinkListIterator:# 手動實現一個鏈表迭代器def __init__(self, node):self.node = nodedef __next__(self):if self.node:cur_node = self.nodeself.node = cur_node.nextreturn cur_node.itemelse:raise StopIterationdef __iter__(self):return selfdef __init__(self, iterable=None):self.head = LinkList.Node(0) # 初始化頭結點self.tail = self.headself.extend(iterable)def append(self, obj): # 添加節點(尾插法)s = LinkList.Node(obj)self.tail.next = sself.tail = sself.head.item += 1 # 鏈表長度+1def extend(self, iterable):for obj in iterable:self.append(obj)def __iter__(self):return self.LinkListIterator(self.head.next) # 從頭節點的下一個開始迭代def __len__(self):return self.head.itemdef __str__(self):return "<<" + ", ".join(map(str, self)) + ">>"li = [i for i in range(10)] lk = LinkList(li) print(lk) # <<0, 1, 2, 3, 4, 5, 6, 7, 8, 9>>

    中介者模式

    暫不討論。

    備忘錄模式

    暫不討論。

    觀察者模式

    內容

    定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時, 所有依賴于它的對象都得到通知并被自動更新。觀察者模式又稱“發布-訂閱”模式。

    比如,我們根據excel表格數據生成餅狀圖、柱狀圖、折線圖,一旦我們更新了excel表格數據,那么這些圖表也會隨之更新。這些圖表就是觀察者。

    角色

    • 抽象主體(Subject)
    • 具體主體(ConcreteSubject)——發布者
    • 抽象觀察者(Observer)
    • 具體觀察者(ConcreteObserver)——訂閱者

    適用場景

    • 當一個抽象模型有兩方面,其中一個方面依賴于另一個方面。將這兩者封裝在獨立對象中以使它們可以各自獨立地改變和復用
    • 當對一個對象的改變需要同時改變其它對象,而不知道具體有多少對象有待改變
    • 當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之,你不希望這些對象是緊密耦合的。

    優點

    • 目標和觀察者之間的抽象耦合最小
    • 支持廣播通信

    示例

    from abc import ABCMeta, abstractmethod# 抽象觀察者/訂閱者 class Observer(metaclass=ABCMeta):@abstractmethoddef update(self, notice):pass# 通知 基類 class Notification(object):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 WeatherNotifications(Notification):def __init__(self, weather_info=None):super().__init__()self.__weather_info = weather_infodef detach(self, obs):super().detach(obs)# obs.__weather_info = None@propertydef weather_info(self):return self.__weather_info@weather_info.setterdef weather_info(self, weather_info):self.__weather_info = weather_infoself.notify() # 自動傳入消息對象self# 具體觀察者/訂閱者 class Subscriber(Observer):def __init__(self):self.weather_info = Nonedef update(self, notification):self.weather_info = notification.weather_info# 實例化天氣消息發布者 notice = WeatherNotifications()# 實例化訂閱者 Lena = Subscriber() Ayhan = Subscriber()# 為天氣消息發布者添加訂閱對象 notice.attach(Lena) notice.attach(Ayhan)# 發布天氣消息 notice.weather_info = '今夜陽光明媚' # 訂閱者收到消息 print(Lena.weather_info) # 今夜陽光明媚 print(Ayhan.weather_info) # 今夜陽光明媚# 移除訂閱者 notice.detach(Ayhan) # 發布最新消息 notice.weather_info = '暴風雨即將來臨' print(Lena.weather_info) # 暴風雨即將來臨 print(Ayhan.weather_info) # 今夜陽光明媚

    狀態模式

    暫不討論。

    策略模式

    內容

    定義一系列的算法,把它們一個個封裝起來,并且使它們可相互替換。本模式使得算法可獨立于使用它的客戶而變化。

    角色

    • 抽象策略(Strategy)
    • 具體策略(ConcreteStrategy)
    • 上下文(Context):連接策略類和高層代碼,可以選擇策略。比如打車時,高峰期和平時,應該選擇不同的策略。

    適用場景

    • 許多相關的類僅僅是行為有異
    • 需要使用一個算法的不同變體
    • 算法使用了客戶端無需知道的數據。比如算法中需要當前時間,那么在Context中自動生成傳入。
    • 一個類中的多種行為以多個條件語句的形式存在,可以將這些行為封裝在不同的策略類中。

    優點

    • 定義了一系列可重用的算法和行為
    • 消除了一些條件語句
    • 可以提供相同行為的不同實現

    缺點

    • 客戶必須了解不同的策略

    示例

    客戶端可以根據需要,選擇排序或歸并策略。

    Python 排序算法參考:http://blog.csdn.net/ayhan_huang/article/details/78564600

    from abc import ABCMeta, abstractmethod import randomclass Sort(metaclass=ABCMeta):@abstractmethoddef sort(self, data):pass# 快排策略 class QuickSort(Sort):def quick_sort(self, data, left, right):if left < right:mid = self.partition(data, left, right)self.quick_sort(data, left, mid - 1)self.quick_sort(data, mid + 1, right)def partition(self, data, left, right):tmp = data[left]while left < right:while left < right and data[right] >= tmp:right -= 1data[left] = data[right]while left < right and data[left] <= tmp:left += 1data[right] = data[left]data[left] = tmpreturn leftdef sort(self, data):print("快速排序")return self.quick_sort(data, 0, len(data) - 1)# 歸并策略 class MergeSort(Sort):def merge(self, data, low, mid, high):i = lowj = mid + 1ltmp = []while i <= mid and j <= high:if data[i] <= data[j]:ltmp.append(data[i])i += 1else:ltmp.append(data[j])j += 1while i <= mid:ltmp.append(data[i])i += 1while j <= high:ltmp.append(data[j])j += 1data[low:high + 1] = ltmpdef merge_sort(self, data, low, high):if low < high:mid = (low + high) // 2self.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 = dataself.strategy = strategydef set_strategy(self, strategy):self.strategy = strategydef do_strategy(self):if self.strategy:self.strategy.sort(self.data)else:raise TypeErrorli = list(range(100000)) random.shuffle(li)context = Context(li, MergeSort()) context.do_strategy()random.shuffle(context.data)context.set_strategy(QuickSort()) context.do_strategy()

    訪問者模式

    暫不討論。

    模板方法模式

    內容

    定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。

    角色

    • 抽象類(AbstractClass):定義抽象的原子操作(鉤子操作);實現一個模板方法作為算法的骨架
    • 具體類(ConcreteClass):實現原子操作

    適用場景

    • 一次性實現一個算法的不變的部分
    • 各個子類中的公共行為應該被提取出來并集中到一個公共父類中以避免代碼重復
    • 控制子類擴展

    示例

    以下以文件處理為例,打開 - 處理 - 關閉 這三步就是不可分割的原子操作。

    # coding : utf-8 # create by ztypl on 2017/5/27from abc import ABCMeta, abstractmethodclass IOHandler(metaclass=ABCMeta):@abstractmethoddef open(self, name):pass@abstractmethoddef deal(self, change):pass@abstractmethoddef close(self):passdef 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 World")

    總結

    以上是生活随笔為你收集整理的python设计模式总结的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 成人午夜视频一区二区播放 | 欧美 日韩 国产 一区 | 精品一区二区三区中文字幕 | 1000部多毛熟女毛茸茸 | 德国艳星videos极品hd | 亚洲精品www久久久久久广东 | 日本福利片在线观看 | 亚洲人交配视频 | 国产亚洲精品码 | 精品动漫3d一区二区三区免费版 | 蜜臀99久久精品久久久久久软件 | 久久久精品人妻一区二区三区色秀 | 国产农村老头老太视频 | 久久久国产精品人人片 | 五月婷婷综合在线 | 亚洲av成人一区二区 | 亚洲国产情侣 | 综合 欧美 亚洲日本 | 中文字幕av网址 | 亚洲精品国产精品乱码在线观看 | 波多野结衣激情视频 | 琪琪成人 | 91日韩欧美 | 久久久久亚洲精品国产 | 亚洲激情a| 国产又粗又猛又黄又爽 | 日韩美女在线视频 | 欧美老女人视频 | 日本在线激情 | 日韩激情 | 丰满人妻一区二区三区免费视频棣 | 福利片第一页 | 亚洲va天堂va欧美ⅴa在线 | 国产精品91在线观看 | 亚洲精品视频网 | 91香蕉嫩草 | 天天射天天干天天操 | 拔插拔插影库 | 国产欧美一区二区三区精品酒店 | 青青青在线免费观看 | 催眠调教后宫乱淫校园 | 亚洲女人天堂 | 日本精品二区 | 可以直接看av的网址 | 国产伦精品一区二区三区妓女下载 | 欧美性xxxxxxxxx | 密臀av一区二区 | 日本少妇吞精囗交 | 成人黄色免费在线观看 | 中国农村一级片 | 亚洲v国产| 黄色国产在线播放 | 日日干夜夜操 | 欧美另类激情 | 精品无码人妻一区二区三区品 | 国产一级黄色 | 午夜肉伦伦 | 日本伦理片在线播放 | 久久精视频 | 日韩tv| 亚洲午夜精品 | 欧美日一本 | 男生和女生一起差差差很痛的视频 | 粉嫩久久99精品久久久久久夜 | 女人的av | 少妇视频一区二区三区 | 国产一级淫片a视频免费观看 | 性视频黄色 | 久久久蜜桃 | 人人玩人人弄 | 日韩av有码 | 超碰超碰超碰超碰 | 精品久久久蜜桃 | 日韩av毛片 | 亚欧洲乱码视频 | 国产精品VideoSex性欧美 | 成人网视频 | 处女朱莉 | chien国产乱露脸对白 | 99热这里只有精品5 国产精品伦子伦免费视频 精品一二三 | 黄色香蕉网站 | 亚州精品国产精品乱码不99按摩 | www.欧美视频 | www.com在线观看 | 99这里有精品视频 | 亚洲欧美另类在线视频 | 欧美另类精品xxxx孕妇 | 精品成人无码久久久久久 | 成年性生交大片免费看 | 在哪看毛片 | 国产亚洲精品网站 | 国内视频一区二区三区 | 精品产国自在拍 | 激情五月俺也去 | 成人精品在线观看视频 | 97插插插| 精品国产一级片 | 鲁一鲁色一色 | 放几个免费的毛片出来看 |