Python的設計模式

設計模式是什麼?

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

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

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

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

設計模式的定義:爲了解決面向對象系統中重要和重複的設計封裝在一塊兒的一種代碼實現框架,可使得代碼更加易於擴展和調用編程

四個基本要素:模式名稱,問題,解決方案,效果設計模式

六大原則:

  • 1.開閉原則:一個軟件實體,如類,模塊和函數應該對擴展開發,對修改關閉.既軟件實體應儘可能在不修改原有代碼的狀況下進行擴展.
  • 2.里氏替換原則:全部引用父類的方法必須能透明的使用其子類的對象
  • 3.依賴倒置原則:高層模塊不該該依賴底層模塊,兩者都應該依賴其抽象,抽象不該該依賴於細節,細節應該依賴抽象,換而言之,要針對接口編程而不是針對實現編程
  • 4.接口隔離原則:使用多個專門的接口,而不是使用單一的總接口,即客戶端不該該依賴那些並不須要的接口
  • 5.迪米特法則:一個軟件實體應該儘量的少與其餘實體相互做用
  • 6.單一直責原則:不要存在多個致使類變動的緣由.即一個類只負責一項職責

主流的設計模式

接口

  定義:一種特殊的類,聲明瞭若干方法,要求繼承該接口的類必須實現這種方法微信

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

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)

一:單例模式

     定義:保證一個類只有一個實例,並提供一個訪問它的全局訪問點框架

     適用場景:當一個類只能有一個實例而客戶能夠從一個衆所周知的訪問點訪問它時dom

     優勢:對惟一實例的受控訪問,至關於全局變量,可是又能夠防止此變量被篡改

*args, **kargs):
#         if cls not in _instance:
#             _instance[cls] = cls(*args, **kargs)
#         return _instance[cls]
#
#     return _singleton
#
#
# @Singleton
# class A(object):
#     a = 1
#
#     def __init__(self, x=0):
#         self.x = x
#
#
# a1 = A(2)
# a2 = A(3)

"""方式三:使用類"""
# import threading
# import time
#
#
# class Singleton(object):
#
#     def __init__(self):
#         # time.sleep(1)
#         pass
#     @classmethod
#     def instance(cls, *args, **kwargs):
#         if not hasattr(Singleton, "_instance"):
#             Singleton._instance = Singleton(*args, **kwargs)
#         return Singleton._instance
#
#
# def task(arg):
#     obj = Singleton.instance()
#     print(obj)
#
#
# for i in range(10):
#     t = threading.Thread(target=task,args=[i,])
#     t.start()

"""解決方法:加鎖"""
# import time
# import threading
#
#
# class Singleton(object):
#     _instance_lock = threading.Lock()
#
#     def __init__(self):
#         time.sleep(1)
#
#     @classmethod
#     def instance(cls, *args, **kwargs):
#         if not hasattr(Singleton, "_instance"):
#             with Singleton._instance_lock:
#                 if not hasattr(Singleton, "_instance"):
#                     Singleton._instance = Singleton(*args, **kwargs)
#         return Singleton._instance
#
#
#
#
# def task(arg):
#     obj = Singleton.instance()
#     print(obj)
#
# for i in range(10):
#     t = threading.Thread(target=task,args=[i,])
#     t.start()
# time.sleep(20)
# obj = Singleton.instance()
# print(obj)

"""方法四:基於__new__方法"""
#
# import threading
#
# class Singleton(object):
#     _instance_lock = threading.Lock()
#
#     def __init__(self):
#         pass
#
#     def __new__(cls, *args, **kwargs):
#         if not hasattr(Singleton, "_instance"):
#             with Singleton._instance_lock:
#                 if not hasattr(Singleton, "_instance"):
#                     Singleton._instance = object.__new__(cls)
#         return Singleton._instance
#
#
# obj1 = Singleton()
# obj2 = Singleton()
# print(obj1,obj2)
#
#
# def task(arg):
#     obj = Singleton()
#     print(obj)
#
#
# for i in range(10):
#     t = threading.Thread(target=task,args=[i,])
#     t.start()
#
"""方法五:元類實現單例模式"""
import threading


class SingletonType(type):
    _instance_lock = threading.Lock()

    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with SingletonType._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
        return cls._instance


class Foo(metaclass=SingletonType):
    def __init__(self,name):
        self.name = name


obj1 = Foo('name')
obj2 = Foo('name')
print(obj1,obj2)
單例模式

二:簡單工廠模式

     定義:不直接向客戶暴露對象建立的實現細節,而是經過一個工廠類來負責建立產品類的實例

     角色:工廠角色,抽象產品角色,具體產品角色

     優勢:隱藏了對象建立代碼的細節,客戶端不須要修改代碼

     缺點:違反了單一職責原則,將建立邏輯集中到一個工廠裏面,當要添加新產品時,違背了開閉原則

# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/17
@Author: Zhang Yafei
"""
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(object):
    """ 工廠角色 """
    @staticmethod
    def create_payment(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)
簡單工廠模式

三:工廠方法模式

     定義:定義一個建立對象的接口(工廠接口),讓子類決定實例化哪一個接口

     角色:抽象工廠角色,具體工廠角色,抽象產品角色,具體產品角色

     適用場景:須要生產多種,大量複雜對象的時候,須要下降代碼耦合度的時候,當系統中的產品類常常須要擴展的時候

     優勢:每一個具體的產品都對應一個具體工廠,不須要修改工廠類的代碼,工廠類能夠不知道它所建立的具體的類,隱藏了對象建立的實現細節

     缺點:每增長一個具體的產品類,就必須增長一個相應的工廠類

# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/17
@Author: Zhang Yafei
"""
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(object):
    """ 工廠角色 """
    @staticmethod
    def create_payment(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)


# 若是要新增支付方式
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)
工廠方法模式

四:抽象工廠模式

   定義:定義一個工廠類接口,讓工廠子類來建立一系列相關或相互依賴的對象

     角色:抽象工廠角色,具體工廠角色,抽象產品角色,具體產品角色,客戶端

     適用場景:系統要獨立於產品的建立和組合時,強調一系列相關產品的對象設計以便進行聯合調試時,提供一個產品類庫,想隱藏產品的具體實現時

     優勢:將客戶端與類的具體實現相分離,每一個工廠建立了一個完整的產品系列,易於交換產品.有利於產品的一致性

     缺點:難以支持新種類的產品

# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/17
@Author: Zhang Yafei
"""
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()
抽象工廠模式

 五:建造者模式

     定義:將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示

     角色:抽象建造者,具體建造者,指揮者,產品

     適用場景:當建立複雜對象的算法應該獨立於對象的組成部分以及它的裝配方式,當構造過程容許被構造的對象有不一樣的表示

     優勢:隱藏了一個產品的內部結構和裝配過程,將構造代碼與表示代碼分開,能夠對構造過程進行更精確的控制

# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/17
@Author: Zhang Yafei
"""
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(object):
    @staticmethod
    def build_player(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)
建造者模式

 六:適配器模式

     定義:將一個接口轉換爲客戶但願的另外一個接口,該模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做

     角色:目標接口,待適配的類,適配器

     適用場景:想使一個已經存在的類,但其接口不符合你的要求.想對一些已經存在的子類.不可能每個都是用子類來進行適配,對象適配器能夠適配其父類接口

# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/17
@Author: Zhang Yafei
"""
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)
適配器模式

 七:組合模式

     定義:將對象組合成樹形結構以表示'部分-總體'的層次結構.組合模式使得用戶對單個對象和組合對象的使用具備一致性

     角色:抽象組件,葉子組件,複合組件,客戶端

     適用場景:表示對象的'部分-總體'層次結構,但願用戶忽略組合對象與單個對象的不一樣,用戶統一使用組合結構中的全部對象

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

     缺點:很難限制組合中的組件

# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/17
@Author: Zhang Yafei
"""
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()
組合模式

八:代理模式

   定義:爲其餘對象提供一種代理以控制對特定對象的訪問

     角色:抽象實體,實體,代理

     適用場景:遠程代理(爲遠程的對象提供代理),虛代理(根據須要建立很大的對象,即懶加載),保護代理(控制對原始對象的訪問,用於具備不一樣訪問權限的對象)

     優勢:遠程代理(能夠隱藏對象位於遠程地址空間的事實),虛代理(可對大對象的加載進行優化),保護代理(容許在訪問一個對象時有一些附加的處理邏輯,例如權限控制)

 -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/17
@Author: Zhang Yafei
"""
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 != 'zhangyafei':
    p = ProxyC(filename)
else:
    p = ProxyB(filename)

print(p.get_content())
代理模式

 九:觀察者模式

     定義:定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴它的對象都會獲得通知並被自動更新.觀察者模式又稱爲'發佈訂閱'模式

     角色:抽象主題,具體主題(發佈者),抽象觀察者,具體觀察者(訂閱者)

     適用場景:當一個抽象模型有兩個方面,其中一個方面依賴於另外一個方面.將二者封裝在獨立的對象中以使它們各自獨立的改變和複用

                    當一個對象的改變須要同時改變其餘對象,並且不知道具體有多少對象以待改變

                    當一個對象必須通知其餘對象,而又不知道其餘對象是誰,即這些對象之間是解耦的

     優勢:目標和觀察者之間的耦合最小,支持廣播通訊

     缺點:多個觀察者之間互不知道對方的存在,所以一個觀察者對主題的修改可能形成錯誤的更新

# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/17
@Author: Zhang Yafei
"""
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)
觀察者模式

十:策略模式

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

     角色:抽象策略,具體策略,上下文

     適用場景:許多相關的類僅僅是行爲有異,需使用一個算法的不一樣變體,算法使用了客戶端無需知道的數據,一個類中的多個行爲以多個條件語句存在能夠將其封裝在不一樣的策略類中

     優勢:定義了一系列可重用的算法和行爲,消除了一些條件語句,可提供相同行爲的不一樣實現

     缺點:客戶必須瞭解不一樣的策略,策略與上下文之間的通訊開銷,增長了對象的數目

# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/17
@Author: Zhang Yafei
"""
import random
from abc import ABCMeta, abstractmethod


# 抽象策略
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()
策略模式

 十一:責任鏈模式

     定義:使多個對象有機會處理請求,從而避免請求的發佈者和接收者之間的耦合關係,將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象能處理它爲止

     角色:抽象處理者,具體處理者,客戶端

     適用場景:有多個對象能夠處理一個請求,哪一個對象處理由運行時決定

     優勢:下降耦合度,一個對象無需知道是其餘哪個對象處理其請求

     缺點:請求不保證被接收,鏈的末端沒有處理或鏈配置錯誤

# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/17
@Author: Zhang Yafei
"""
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)
責任者模式一
# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/17
@Author: Zhang Yafei
"""
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__

# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/17
@Author: Zhang Yafei
"""


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)
迭代器模式

十三:模板方法模式

     定義:定義一個操做中算法的骨架,將一些步驟延遲到子類中,模板方法使得子類能夠不改變一個算法的結構便可重定義該算法某些特定的步驟

     角色:抽象類(定義抽象的原子操做,實現一個模板方法做爲算法的骨架),具體類(實現原子操做)

     適用場景:一次性實現一個算法不變的部分,各個子類的公共行爲,應該被提取出來集中到公共的父類中以免代碼重複,控制子類擴展

# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/17
@Author: Zhang Yafei
"""
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')
模板方法模式
相關文章
相關標籤/搜索