Python 設計模式

什麼是設計模式?

設計模式是通過總結、優化的,對咱們常常會碰到的一些編程問題的可重用解決方案。一個設計模式並不像一個類或一個庫那樣可以直接做用於咱們的代碼。反之,設計模式更爲高級,它是一種必須在特定情形下實現的一種方法模板。設計模式不會綁定具體的編程語言。一個好的設計模式應該可以用大部分編程語言實現(若是作不到所有的話,具體取決於語言特性)。最爲重要的是,設計模式也是一把雙刃劍,若是設計模式被用在不恰當的情形下將會形成災難,進而帶來無窮的麻煩。然而若是設計模式在正確的時間被用在正確地地方,它將是你的救星。javascript

起初,你會認爲「模式」就是爲了解決一類特定問題而特別想出來的明智之舉。說的沒錯,看起來的確是經過不少人一塊兒工做,從不一樣的角度看待問題進而造成的一個最通用、最靈活的解決方案。也許這些問題你曾經見過或是曾經解決過,可是你的解決方案極可能沒有模式這麼完備。html

雖然被稱爲「設計模式」,可是它們同「設計「領域並不是緊密聯繫。設計模式同傳統意義上的分析、設計與實現不一樣,事實上設計模式將一個完整的理念根植於程序中,因此它可能出如今分析階段或是更高層的設計階段。頗有趣的是由於設計模式的具體體現是程序代碼,所以可能會讓你認爲它不會在具體實現階段以前出現(事實上在進入具體實現階段以前你都沒有意識到正在使用具體的設計模式)。java

能夠經過程序設計的基本概念來理解模式:增長一個抽象層。抽象一個事物就是隔離任何具體細節,這麼作的目的是爲了將那些不變的核心部分從其餘細節中分離出來。當你發現你程序中的某些部分常常由於某些緣由改動,而你不想讓這些改動的部分引起其餘部分的改動,這時候你就須要思考那些不會變更的設計方法了。這麼作不只會使代碼可維護性更高,並且會讓代碼更易於理解,從而下降開發成本。python

這裏列舉了三種最基本的設計模式:算法

  1. 建立模式,提供實例化的方法,爲適合的情況提供相應的對象建立方法。
  2. 結構化模式,一般用來處理實體之間的關係,使得這些實體可以更好地協同工做。
  3. 行爲模式,用於在不一樣的實體建進行通訊,爲實體之間的通訊提供更容易,更靈活的通訊方法。

設計模式的六大原則

開閉原則:軟件實體如類,模塊,函數應該對擴展開放,對修改關閉 
里氏替換原則:全部飲用積累的地方必須透明地使用其子類的對象
依賴倒置原則:高層模塊不該該依賴低層模塊,兩者都應該依賴其抽象;抽象不該該依賴細節,細節應該依賴抽象。換言之,要針對接口編程,而不是針對實現編程
接口隔離原則:使用多個專門的接口,而不該該使用單一的總接口,即客戶端不該該依賴那麼它不須要的接口
迪米特法則:軟件實體應當儘量少地與其餘實體發生相互做用
單一職責原則:不要存在多於一個致使類變動的緣由。通俗的說,一個類只負責一項職責

 

哪些設計模式?

建立型shell

1. Factory Method(工廠方法)編程

2. Abstract Factory(抽象工廠)設計模式

3. Builder(建造者)微信

4. Prototype(原型)app

5. Singleton(單例)

結構型

6. Adapter Class/Object(適配器)

7. Bridge(橋接)

8. Composite(組合)

9. Decorator(裝飾)

10. Facade(外觀)

11. Flyweight(享元)

12. Proxy(代理)

行爲型

13. Interpreter(解釋器)

14. Template Method(模板方法)

15. Chain of Responsibility(責任鏈)

16. Command(命令)

17. Iterator(迭代器)

18. Mediator(中介者)

19. Memento(備忘錄)

20. Observer(觀察者)

21. State(狀態)

22. Strategy(策略)

23. Visitor(訪問者)

 

 

建立型模式

一、單例模式

看着礙眼,首先把以前提到過的最容易理解的講掉。

內容:保證一個類只有一個實例,並提供一個訪問它的全局訪問點
優勢:
    1、對惟一實例的受控訪問
    二、單例至關於全局變量,但防止了命名空間被污染

代碼實現:

class Singleton(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, cls).__init__(cls)
        return cls._instance


class MyClass(Singleton):
    def __init__(self, name=None):
        self.name = name

 

先補充一個概念

類接口

#python 類的第一種接口寫法


class Payment:
    def pay(self, money):
        raise NotImplementedError  # 報錯,沒用重寫此方法


class Alipay(Payment):
    def pay(self, money):
        print('支付寶支付%s元' % money)


class Wechatpay(Payment):
    def pay(self, money):
        print('微信支付%s元' % money)


class Testpay(Payment):
    def fuqian(self, money):
        print('money', money)


def payx(payment, money):
    payment.pay(money)
payx(Testpay(), 100)


# 第二種接口寫法
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 Wechatpay(Payment):
    pass

def payx(payment, money):
    payment.pay(money)


payx(Wechatpay(), 100)

在Python中實現抽象方法最簡單地方式是:上面的接口一的寫法,任何繼承自Payment的類必須覆蓋實現方法pay,不然會拋出異常。這種抽象方法的實現有它的弊端,若是你寫一個類繼承Pizza,可是忘記實現get_radius,異常只有在你真正使用的時候纔會拋出來。

還有一種方式可讓錯誤更早的觸發,使用Python提供的abc模塊,對象被初始化以後就能夠拋出異常:上面的接口二的寫法。使用@abstractmethod後,當你嘗試初始化Pyament或者任何子類的時候立馬就會獲得一個TypeError,而無需等到真正調用pay的時候才發現異常。

 

簡單工廠模式

內容:不直接向客戶端暴露對象建立的實現細節,而是經過一個工廠類來負責建立產品類的實例
角色:
  一、工廠角色 PaymentFactory

  二、抽象產品角色 Payment

  三、具體產品角色 Alipay & WechatPay
優勢:
  一、隱藏了對象建立的實現細節  # 實例化過程,還有餘額寶建立過程
  二、客戶端不須要修改代碼  # 客戶端只有調用,傳入參數就好
缺點:
  一、違反了單一職責原則,將建立邏輯集中到一個工廠類裏
  二、當添加新產品時,須要修改工廠代碼,違反了開閉原則

#!/usr/bin/env python3
# encoding: utf-8
# Author: Dandy
from abc import abstractmethod, ABCMeta


class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass


class Alipay(Payment):

    def __init__(self, enabled_yuebao = False):
        self.enabled_yuebao = enabled_yuebao

    def pay(self, money):
        if self.enabled_yuebao:
            print('餘額寶支付%s元' % money)
        else:
            print('支付寶支付%s元' % money)


class Wechatpay(Payment):
    def pay(self, money):
        print('微信支付%s元' % money)


class PaymentFactory:
    def create_payment(self, method):
        if method == 'alipay':
            return Alipay()
        elif method == 'yuebaopay':
            return Alipay(True)
        elif method == 'wechatpay':
            return Wechatpay()
        else:
            raise NameError(method)


f = PaymentFactory()
p = f.create_payment('yuebaopay')
p.pay(100)

# 不暴露出建立對象的實現細節,而直接將實例化對象返回

 

具體產品繼承並重寫抽象類,工廠實例化具體產品到對象。 

 

工廠方法模式(Factory Method)

 

內容:定義一個用於建立對象的接口(工廠接口),讓子類決定實例化哪個產品類。Factory Method 使個類的實例化延遲到其子類。

角色:
  一、抽象工廠角色  payment factory
  二、具體工廠角色  allipay factory
  三、抽象產品角色  payment
  四、具體產品角色  alipay

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

使用場景

  一、須要生產多種,大量複雜對象的時候
  二、須要下降耦合度的時候
  三、當系統中的產品種類須要常常擴展的時候

優勢:
  一、每一個具體產品都對應一個具體工廠類,不須要修改工廠類代碼
  二、隱藏了對象建立的實現細節
缺點:
  一、每增長一個具體產品類,就必須增長一個相應的具體工廠類 

from abc import abstractmethod, ABCMeta


class PaymentFactory(metaclass=ABCMeta):
    @abstractmethod
    def create_payment(self):
        pass


class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass


class AlipayFactory(PaymentFactory):

    def create_payment(self):
        return Alipay()


class ApplePayFactory(PaymentFactory):
    def create_payment(self, money):
        return ApplePay()


class Alipay(Payment):
    def pay(self, money):
        print('支付寶支付%s元' % money)


class ApplePay(Payment):
    def pay(self, money):
        print('蘋果支付%s元' % money)


ali = AlipayFactory()
ali = ali.create_payment()
ali.pay(120)

抽象產品類被具體產品類繼承,具體工廠繼承抽象工廠並調用具體產品,不一樣的具體工廠返回不一樣的相對應的具體產品對象給用戶。

 

 

抽象工廠模式(Abstract Factory)

抽象工廠模式
內容:定義一個工廠類接口,讓工廠子類來建立一系列相關或相互依賴的對象
例如:生產一部手機須要,手機殼,cpu,操做系統三類對象進行組裝,其中每類對象都有不一樣的種類。對每一個具體工廠,分別生產一部手機所須要的三個對象。
角色:
  一、抽象工廠角色  PhoneFactory
  二、具體工廠角色  AppleFactory
  三、抽象產品角色  PhoneShell、CPU、OS
  四、具體產品角色  AppleShell
  五、客戶端  
相比工廠方法模式,抽象工廠模式中的每一個具體工廠都生產一套產品。
適用場景:
  一、系統要獨立於產品的建立和組合時
  二、強調一系列相關產品對象的設計以便進行聯合使用時
  三、提供一個產品的類庫,想隱藏產品的具體實現時
優勢:
  一、將客戶端與類的具體實現分離
  二、每一個工廠建立了一個完整的產品系列,使得易於交換產品系列
  三、有利於產品的一致性(即產品之間的約束關係)
缺點:
  一、難以支持新種類的(抽象)產品

代碼

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 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('蘋果')


class Android(OS):
    def show_os(self):
        print('Android系統')


class IOS(OS):
    def show_os(self):
        print('IOS 系統')


# ***************抽象工廠**************
class PhoneFactory(metaclass=ABCMeta):
    @abstractmethod
    def make_shell(self):
        pass

    @abstractmethod
    def make_cpu(self):
        pass

    @abstractmethod
    def make_os(self):
        pass


# ***************** 具體工廠 *************

class AppleFactory(PhoneFactory):
    def make_cpu(self):
        return AppleCPU()

    def make_os(self):
        return IOS()

    def make_shell(self):
        return AppleShell()


class HuaweiFactory(PhoneFactory):
    def make_cpu(self):
        return SnapDragonCPU()

    def make_shell(self):
        return BigShell()

    def make_os(self):
        return Android()

# ************************ 客戶端 **************************
class Phone:
    def __init__(self, cpu, os, shell):
        self.cpu = cpu
        self.os = os
        self.shell = shell

    def 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(AppleFactory())
p1.show_info()

 

 

建造者模式

 

內容:將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示。
角色:
  一、抽象建造者
  二、具體建造者
  三、指揮者
  四、產品
建造者模式與抽象工廠模式類似,也用來建立複雜對象。主要區別在於見照着模式着重一步步構造一個複雜對象,二抽象工廠模式着重於多個系列的產品對象
適用場景:
  一、當建立複雜對象的算法(director),應該獨立於該對象的組成部分以及他們的裝配方法(builder)時
  二、當構造過程容許被構造的對象有不一樣的表示時(不一樣builder)
優勢:
  一、隱藏了一個產品的內部結構和裝配過程
  二、將構造代碼與表示代碼分開
  三、能夠對構造過程進行更精細的控制

 

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.arm, self.body, self.leg)

# *************************** 抽象建造者 *********************************


class PlayerBuilder(metaclass=ABCMeta):
    @abstractmethod
    def build_face(self):
        pass

    @abstractmethod
    def build_arm(self):
        pass

    @abstractmethod
    def build_body(self):
        pass

    @abstractmethod
    def build_leg(self):
        pass

    @abstractmethod
    def get_player(self):
        pass


# *************************** 具體建造者 *********************************

class BeautifulWomenBuilder(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 PlayDirector:
    def build_player(self, builder):
        builder.build_face()
        builder.build_body()
        builder.build_leg()
        builder.build_arm()
        return builder.get_player()


director = PlayDirector()
builder = BeautifulWomenBuilder()
person = director.build_player(builder)

print(person)

 

 

建立型模式小結


適用abstra factory、 prototype或者builder的設計甚至比適用factory method的那些設計更靈活,但他們也更加複雜。一般,設計以適用Factory method開始,而且設計者發現須要更大的靈活性時,設計便會向其餘建立模式演化。當你在設計標準之間進行權衡的時候,瞭解多個模式能夠給你提供更多的選擇餘地。
一、依賴於繼承的建立型模式:工廠方法模式
二、依賴於組合的建立型模式:抽象工廠模式,建立者模式


工廠方法模式:一類產品,每類產品有多種
抽象工廠模式:多類產品,每類產品有多種
建造者模式:多類產品,每類產品有一種,目的是把多種產品攢成大產品

 

 

結構型模式

適配器模式

 

 

內容:將一個類的接口轉換成客戶但願的另外一個接口。適配器模式使得本來因爲接口不兼容二不能一塊兒工做的那些類能夠一塊兒工做。
角色:
  一、目標接口
  二、帶適配的類
  三、適配器
兩種實現方式:
類適配器:多繼承
對象適配器:組合
適用場景
  一、想使用一個已經存在的類,而它的接口不符合你的要求
  二、(對象適配器)想使用一些已經存在的子類,但不能對每個都進行子類化以匹配它們的接口。對象適配器能夠適配它的父親接口。

 代碼:

from abc import abstractmethod, ABCMeta


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 WeiXinZhiFu:
    def fuqian(self, money):
        print('微信支付%s元' % money)


class WangYinZhiFu:
    def fuqian(self, money):
        print('網銀支付%s元' % money)


# 類適配器寫法, 用繼承
class WechatPay(Payment, WeiXinZhiFu):
    def pay(self, money):
        self.fuqian(money)


# 對象適配器  組合
class PayAdapter(Payment):
    def __init__(self, payment):
        self.payment = payment

    def pay(self, money):
        if hasattr(self, "pay"):
            return self.payment.pay(money)
        else:
            return self.payment.fuqian(money)


# paym = WechatPay()
# paym.pay(1000)

paym = PayAdapter(WangYinZhiFu())
paym.pay(1000)

 

 

組合模式

 

內容:將對象組合成樹形結構以表示「部分-總體」的層次結構。組合模式使得用戶對單個對象和最合對象的使用具備一致性。
角色:
  一、抽象組件
  二、葉子組件
  三、複合組件
  四、客戶端
適用場景:
  一、表示對象的「部分-總體」層次結構(特別是結構是遞歸的)
  二、但願用戶忽略組合對象與單個對象的不一樣,用戶贊成地使用組合結構中的對象
優勢:
  一、定義了包含基本對象和組合對象的類層次結構
  二、簡化客戶端代碼,即客戶端能夠一致地使用組合對象和單個對象
  三、更容易增長新類型的組件
缺點:
  一、很難限制組合中的組件

代碼:

from abc import abstractmethod, ABCMeta


class Graphic(metaclass=ABCMeta):

    @abstractmethod
    def draw(self):
        pass

    @abstractmethod
    def add(self):
        pass

    def getchildren(self):
        pass


class Point(Graphic):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def draw(self):
        print(self)

    def add(self, graphic):
        raise TypeError

    def getchildren(self):
        raise TypeError

    def __str__(self):
        return "點(%s, %s)" % (self.x, self.y)


class Line(Graphic):
    def __init__(self, p1, p2):
        self.p1 = p1
        self.p2 = p2

    def draw(self):
        print(self)

    def add(self, graphic):
        raise TypeError

    def __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.children

    def draw(self):
        print('-----複合圖形-----')
        for g in self.children:
            g.draw()
        print('------END-----')


# p1 = Point(1, 2)
# p2 = Point(3, 4)
# l = Line(p1, p2)
# print(l)

pic1 = Picture()
pic1.add(Point(1, 4))
pic1.add(Line(Point(1, 2), Point(3, 2)))
pic1.add(Line(Point(7, 8), Point(9, 4)))

pic2 = Picture()
pic2.add(Point(-1, -1))
pic2.add(Line(Point(-1, -2), Point(3, 2)))

pic = Picture()
pic.add(pic1)
pic.add(pic2)

pic.draw()

 

裝飾模式

意圖: 
動態地給一個對象添加一些額外的職責。就增長功能來講,Decorator 模式相比生成子類更爲靈活。 
適用性:

 在不影響其餘對象的狀況下,以動態、透明的方式給單個對象添加職責。

 處理那些能夠撤消的職責。

當不能採用生成子類的方法進行擴充時。一種狀況是,可能有大量獨立的擴展,爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增加。另外一種狀況多是由於類定義被隱藏,或類定義不能用於生成子類。

#!/usr/bin/python
#coding:utf8
'''
Decorator
'''
 
class foo(object):
    def f1(self):
        print("original f1")
 
    def f2(self):
        print("original f2")
 
 
class foo_decorator(object):
    def __init__(self, decoratee):
        self._decoratee = decoratee
 
    def f1(self):
        print("decorated f1")
        self._decoratee.f1()
 
    def __getattr__(self, name):
        return getattr(self._decoratee, name)
 
u = foo()
v = foo_decorator(u)
v.f1()
v.f2()

 

 

 

 

代理模式

 


內容:爲其餘對象提供一種代理以控制對這個對象的訪問
角色:
  一、抽象實體
  二、實體
  三、代理
適用場景:
  一、遠程代理:爲遠程的對象提供代理
  二、虛代理:根據須要建立很大的對象
  三、保護代理:控制對原始對象的訪問,用於對象有不一樣訪問權限時
優勢:
  一、遠程代理:能夠隱藏對象位於遠程地址空間的事實
  二、虛代理:能夠進行優化,例如根據要求建立對象
  三、保護代理:容許在訪問一個對象時有一些附加的內務處理

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)  # 處理結果存在content裏面

    def get_content(self):  # get_content只是獲取最終結果
        return self.subj.get_content()


# ************************** 虛代理 ****************************

class ProxyB(Subject):
    def __init__(self, filename):  # 實例化的時候只是保存文件名
        self.filename = filename
        self.subj = None

    def get_content(self):  # 調用get_content的時候再執行處理
        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 = ProxyA(filename)

p.get_content()

 

 

行爲型模式

責任鏈模式

 


內容:是多個對象都有機會處理請求,從而避免請求的發送和接受者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,知道有一個對象處理它爲止。
角色:
  一、抽象處理者
  二、具體處理者
  三、客戶端
例:
  一、請假部門批准:lead ==》 部門經理 ==〉 總經理
  二、javascript事件浮升機制

代碼:

from abc import ABCMeta, abstractmethod


class Handler(metaclass=ABCMeta):
    @abstractmethod
    def handle_leave(self, day):
        pass


class GeneralManagerHandler(Handler):
    def handle_leave(self, day):
        if day < 10:
            print('總經理批准%d天假' % day)
        else:
            print('呵呵')


class DepartmentManagerHandler(Handler):
    def __init__(self):
        self.successor = GeneralManagerHandler()

    def handle_leave(self, day):
        if day < 7:
            print('部門經理批准%d天假' % day)
        else:
            print('部門經理無權准假')
            self.successor.handle_leave(day)


class ProjectDirectorHandler(Handler):
    def __init__(self):
        self.successor = DepartmentManagerHandler()

    def handle_leave(self, day):
        if day < 3:
            print('項目主管批准%d天假' % day)
        else:
            print('項目主管無權准假')
            self.successor.handle_leave(day)


day = 10
h = ProjectDirectorHandler()
h.handle_leave(day)

還有個高端點的實例:

# ******************* 高級點的例子--模仿js時間處理 ***************************
class Handler(metaclass=ABCMeta):
    @abstractmethod
    def add_event(self):
        pass

    @abstractmethod
    def handle(self):
        pass


class BodyHandler(Handler):
    def __init__(self):
        self.func = None

    def add_event(self, func):
        self.func = func

    def handle(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 handle(self):
        if self.func:
            return self.func()
        else:
            return self.successor.handle()


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)

div['event_handler'].handle()

 

觀察者模式

 


內容:定義對象見的一種一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於它的對象都獲得通知並被自動更新。觀察者模式又稱爲「發佈-訂閱」模式
角色:
  一、抽象主題
  二、具體主題 -- 發佈者
  三、抽象觀察者
  三、具體觀察者 -- 訂閱者
適用場景:
  一、當一個抽象模型有兩方面,其中一個方面依賴於另外一個方面。將這二者封裝在獨立對象中以使它們能夠各自獨立地改變和複用。
  二、當對一個對象的改變須要同時改變其餘對象,而不知道具體有多少對象有待改變。
  三、當一個對象必須通知其餘對象,而它又不能假定其餘對象是誰。換言之,你不但願這些對象是緊密耦合的。
優勢:
  一、目標和觀察者之間的抽象耦合最少
  二、支持廣播通訊
缺點:
  一、多個觀察者之間互不知道對方存在,所以一個觀察者對主題的修改可能照成錯誤的更新。

代碼:

'''
Observer
'''
 
 
class Subject(object):
    def __init__(self):
        self._observers = []
 
    def attach(self, observer):
        if not observer in self._observers:
            self._observers.append(observer)
 
    def detach(self, observer):
        try:
            self._observers.remove(observer)
        except ValueError:
            pass
 
    def notify(self, modifier=None):
        for observer in self._observers:
            if modifier != observer:
                observer.update(self)
 
# Example usage
class Data(Subject):
    def __init__(self, name=''):
        Subject.__init__(self)
        self.name = name
        self._data = 0
 
    @property
    def data(self):
        return self._data
 
    @data.setter
    def data(self, value):
        self._data = value
        self.notify()
 
class HexViewer:
    def update(self, subject):
        print('HexViewer: Subject %s has data 0x%x' %
              (subject.name, subject.data))
 
class DecimalViewer:
    def update(self, subject):
        print('DecimalViewer: Subject %s has data %d' %
              (subject.name, subject.data))
 
# Example usage...
def main():
    data1 = Data('Data 1')
    data2 = Data('Data 2')
    view1 = DecimalViewer()
    view2 = HexViewer()
    data1.attach(view1)
    data1.attach(view2)
    data2.attach(view2)
    data2.attach(view1)
 
    print("Setting Data 1 = 10")
    data1.data = 10
    print("Setting Data 2 = 15")
    data2.data = 15
    print("Setting Data 1 = 3")
    data1.data = 3
    print("Setting Data 2 = 5")
    data2.data = 5
    print("Detach HexViewer from data1 and data2.")
    data1.detach(view2)
    data2.detach(view2)
    print("Setting Data 1 = 10")
    data1.data = 10
    print("Setting Data 2 = 15")
    data2.data = 15
 
if __name__ == '__main__':
    main()

 

策略模式

 

內容:定義一系列的算法,把他們一個個封裝起來,而且使它們能夠相互替換。本模式使得算法可獨立於使用它的客戶而變化。
角色:
  一、抽象策略
  二、具體策略
  三、上下文
適用場景:
  一、許多相關的類僅僅是行爲有異
  二、須要使用一個算法的不一樣變體
  三、算法使用了客戶端無需知道的數據
  四、一個類中的多種行爲以多個條件語句的形式存在,能夠將這些行爲封裝在不一樣的策略中。
優勢:
  一、定義了一系列可重用的算法和行爲
  二、消除了一些條件語句
  三、能夠提供相同行爲的不一樣實現
缺點:
  一、客戶必須瞭解不一樣的策略
  二、策略與上下文之間的通訊開銷
  三、增長了對象的數目

代碼:

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.partition(data, left, right)
            self.quick_sort(data, left, mid - 1)
            self.quick_sort(data, mid + 1, right)

    def partition(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
        # print(ltmp)
        data[low: high + 1] = ltmp

    def mergesort(self, data, low, high):
        if low < high:
            mid = (low + high) // 2
            self.mergesort(data, low, mid)
            self.mergesort(data, mid + 1, high)
            self.merge(data, low, mid, high)

    def sort(self, data):
        print('歸併排序')
        return self.mergesort(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(10000))
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 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 world')

 

大概就抽取一些重要的介紹,具體的能夠上網找找blog看看

好比:https://www.cnblogs.com/Liqiongyu/p/5916710.html

或者大王的:https://www.cnblogs.com/alex3714/articles/5760582.html

相關文章
相關標籤/搜索