設計模式(Design Patterns)html
——可複用面向對象軟件的基礎python
設計模式(Design pattern)是一套被反覆使用、多數人知曉的、通過分類編目的、代碼設計經驗的總結。使用設計模式是爲了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 毫無疑問,設計模式於己於他人於系統都是多贏的,設計模式使代碼編制真正工程化,設計模式是軟件工程的基石,如同大廈的一塊塊磚石同樣。項目中合理的運用設計模式能夠完美的解決不少問題,每種模式在如今中都有相應的原理來與之對應,每個模式描述了一個在咱們周圍不斷重複發生的問題,以及該問題的核心解決方案,這也是它能被普遍應用的緣由。linux
經典的《設計模式》一書概括出23種設計模式,這23種模式又可歸爲,建立型、結構型和行爲型3大類程序員
前面講過,社會化的分工愈來愈細,天然在軟件設計方面也是如此,所以對象的建立和對象的使用分開也就成爲了必然趨勢。由於對象的建立會消耗掉系統的不少資源,因此單獨對對象的建立進行研究,從而可以高效地建立對象就是建立型模式要探討的問題。這裏有6個具體的建立型模式可供研究,它們分別是:web
簡單工廠模式(Simple Factory);算法
工廠方法模式(Factory Method);spring
抽象工廠模式(Abstract Factory);編程
建立者模式(Builder);設計模式
原型模式(Prototype);安全
單例模式(Singleton)。
說明:嚴格來講,簡單工廠模式不是GoF總結出來的23種設計模式之一。
在解決了對象的建立問題以後,對象的組成以及對象之間的依賴關係就成了開發人員關注的焦點,由於如何設計對象的結構、繼承和依賴關係會影響到後續程序的維護性、代碼的健壯性、耦合性等。對象結構的設計很容易體現出設計人員水平的高低,這裏有7個具體的結構型模式可供研究,它們分別是:
外觀模式(Facade);
適配器模式(Adapter);
代理模式(Proxy);
裝飾模式(Decorator);
橋模式(Bridge);
組合模式(Composite);
享元模式(Flyweight)
在對象的結構和對象的建立問題都解決了以後,就剩下對象的行爲問題了,若是對象的行爲設計的好,那麼對象的行爲就會更清晰,它們之間的協做效率就會提升,這裏有11個具體的行爲型模式可供研究,它們分別是:
模板方法模式(Template Method);
觀察者模式(Observer);
狀態模式(State);
策略模式(Strategy);
職責鏈模式(Chain of Responsibility);
命令模式(Command);
訪問者模式(Visitor);
調停者模式(Mediator);
備忘錄模式(Memento);
迭代器模式(Iterator);
解釋器模式(Interpreter)。
一、開閉原則(Open Close Principle)
開閉原則就是說對擴展開放,對修改關閉。在程序須要進行拓展的時候,不能去修改原有的代碼,實現一個熱插拔的效果。因此一句話歸納就是:爲了使程序的擴展性好,易於維護和升級。想要達到這樣的效果,咱們須要使用接口和抽象類,後面的具體設計中咱們會提到這點。
二、里氏代換原則(Liskov Substitution Principle)
里氏代換原則(Liskov Substitution Principle LSP)面向對象設計的基本原則之一。 里氏代換原則中說,任何基類能夠出現的地方,子類必定能夠出現。 LSP是繼承複用的基石,只有當衍生類能夠替換掉基類,軟件單位的功能不受到影響時,基類才能真正被複用,而衍生類也可以在基類的基礎上增長新的行爲。里氏代換原則是對「開-閉」原則的補充。實現「開-閉」原則的關鍵步驟就是抽象化。而基類與子類的繼承關係就是抽象化的具體實現,因此里氏代換原則是對實現抽象化的具體步驟的規範。—— From Baidu 百科
三、依賴倒轉原則(Dependence Inversion Principle)
這個是開閉原則的基礎,具體內容:是對接口編程,依賴於抽象而不依賴於具體。
四、接口隔離原則(Interface Segregation Principle)
這個原則的意思是:使用多個隔離的接口,比使用單個接口要好。仍是一個下降類之間的耦合度的意思,從這兒咱們看出,其實設計模式就是一個軟件的設計思想,從大型軟件架構出發,爲了升級和維護方便。因此上文中屢次出現:下降依賴,下降耦合。
五、迪米特法則(最少知道原則)(Demeter Principle)
爲何叫最少知道原則,就是說:一個實體應當儘可能少的與其餘實體之間發生相互做用,使得系統功能模塊相對獨立。
六、合成複用原則(Composite Reuse Principle)
原則是儘可能使用合成/聚合的方式,而不是使用繼承。
工廠模式(Factory Pattern)是 Java 中最經常使用的設計模式之一。這種類型的設計模式屬於建立型模式,它提供了一種建立對象的最佳方式。
在工廠模式中,咱們在建立對象時不會對客戶端暴露建立邏輯,而且是經過使用一個共同的接口來指向新建立的對象。
意圖:
定義一個用於建立對象的接口,讓子類決定實例化哪個類。Factory Method 使一個類的實例化延遲到其子類。
適用性:
當一個類不知道它所必須建立的對象的類的時候。
當一個類但願由它的子類來指定它所建立的對象的時候。
當類將建立對象的職責委託給多個子類中的某一個。
class ShapeFactory(object): '''工廠類''' def getShape(self): return self.shape_name class Circle(ShapeFactory): def __init__(self): self.shape_name = "Circle" def draw(self): print('draw circle') class Rectangle(ShapeFactory): def __init__(self): self.shape_name = "Retangle" def draw(self): print('draw Rectangle') class Shape(object): '''接口類,負責決定建立哪一個ShapeFactory的子類''' def create(self, shape): if shape == 'Circle': return Circle() elif shape == 'Rectangle': return Rectangle() else: return None fac = Shape() obj = fac.create('Circle') obj.draw() obj.getShape()
優勢:客戶端不須要修改代碼。
缺點: 當須要增長新的運算類的時候,不只需新加運算類,還要修改工廠類,違反了開閉原則。
這個和簡單工廠有區別,簡單工廠模式只有一個工廠,工廠方法模式對每個產品都有相應的工廠
好處:增長一個運算類(例如N次方類),只須要增長運算類和相對應的工廠,兩個類,不須要修改工廠類。
缺點:增長運算類,會修改客戶端代碼,工廠方法只是把簡單工廠的內部邏輯判斷移到了客戶端進行。
class ShapeFactory(object): '''工廠類''' def getShape(self): return self.shape_name class Circle(ShapeFactory): def __init__(self): self.shape_name = "Circle" def draw(self): print('draw circle') class Rectangle(ShapeFactory): def __init__(self): self.shape_name = "Retangle" def draw(self): print('draw Rectangle') class ShapeInterfaceFactory(object): '''接口基類''' def create(self): '''把要建立的工廠對象裝配進來''' raise NotImplementedError class ShapeCircle(ShapeInterfaceFactory): def create(self): return Circle() class ShapeRectangle(ShapeInterfaceFactory): def create(self): return Rectangle() shape_interface = ShapeCircle() obj = shape_interface.create() obj.getShape() obj.draw() shape_interface2 = ShapeRectangle() obj2 = shape_interface2.create() obj2.draw()
下面這個是用學校\課程來描述了一個工廠模式
''' 工廠方法模式是簡單工廠模式的衍生,解決了許多簡單工廠模式的問題。 首先徹底實現‘開-閉 原則’,實現了可擴展。其次更復雜的層次結構,能夠應用於產品結果複雜的場合。 工廠方法模式的對簡單工廠模式進行了抽象。有一個抽象的Factory類(能夠是抽象類和接口),這個類將不在負責具體的產品生產,而是隻制定一些規範,具體的生產工做由其子類去完成。在這個模式中,工廠類和產品類每每能夠依次對應。即一個抽象工廠對應一個抽象產品,一個具體工廠對應一個具體產品,這個具體的工廠就負責生產對應的產品。 工廠方法模式(Factory Method pattern)是最典型的模板方法模式(Templete Method pattern)應用。 ''' class AbstractSchool(object): name = '' addr = '' principal = '' def enroll(self,name,course): pass def info(self): pass class AbstractCourse(object): def __init__(self,name,time_range,study_type,fee): self.name = name self.time_range = time_range self.study_type = study_type self.fee = fee def enroll_test(self): ''' 參加這門課程前須要進行的測試 :return: ''' print("課程[%s]測試中..." % self.name) def print_course_outline(self): '''打印課程大綱''' pass class LinuxOPSCourse(AbstractCourse): ''' 運維課程 ''' def print_course_outline(self): outline=''' Linux 基礎 Linux 基本服務使用 Linux 高級服務篇 Linux Shell編程 ''' print(outline) def enroll_test(self): print("不用測試,是我的就能學...") class PythonCourse(AbstractCourse): '''python自動化開發課程''' def print_course_outline(self): outline=''' python 介紹 python 基礎語法 python 函數式編程 python 面向對象 python 網絡編程 python web開發基礎 ''' print(outline) def enroll_test(self): print("-------python入學測試-------") print("-------500道題答完了-------") print("-------經過了-------") class BJSchool(AbstractSchool): name = "老男孩北京校區" def create_course(self,course_type): if course_type == 'py_ops': course = PythonCourse("Python自動化開發", 7,'面授',11000) elif course_type == 'linux': course = LinuxOPSCourse("Linux運維課程", 5,'面授',12800) return course def enroll(self,name,course): print("開始爲新學員[%s]辦入學手續... "% name) print("幫學員[%s]註冊課程[%s]..." % (name,course)) course.enroll_test() def info(self): print("------[%s]-----"%self.name) class SHSchool(AbstractSchool): name = "老男孩上海分校" def create_course(self,course_type): if course_type == 'py_ops': course = PythonCourse("Python自動化開發", 8,'在線',6500) elif course_type == 'linux': course = LinuxOPSCourse("Linux運維課程", 6,'在線',8000) return course def enroll(self,name,course): print("開始爲新學員[%s]辦入學手續... "% name) print("幫學員[%s]註冊課程[%s]..." % (name,course)) #course.level_test() def info(self): print("--------[%s]-----" % self.name ) school1 = BJSchool() school2 = SHSchool() school1.info() c1=school1.create_course("py_ops") school1.enroll("張三",c1) school2.info() c2=school1.create_course("py_ops") school2.enroll("李四",c2)
每個模式都是針對必定問題的解決方案。抽象工廠模式與工廠方法模式的最大區別就在於,工廠方法模式針對的是一個產品等級結構;而抽象工廠模式則須要面對多個產品等級結構。
在學習抽象工廠具體實例以前,應該明白兩個重要的概念:產品族和產品等級。
所謂產品族,是指位於不一樣產品等級結構中,功能相關聯的產品組成的家族。好比AMD的主板、芯片組、CPU組成一個家族,Intel的主板、芯片組、CPU組成一個家族。而這兩個家族都來自於三個產品等級:主板、芯片組、CPU。一個等級結構是由相同的結構的產品組成,示意圖以下:
顯然,每個產品族中含有產品的數目,與產品等級結構的數目是相等的。產品的等級結構與產品族將產品按照不一樣方向劃分,造成一個二維的座標系。橫軸表示產品的等級結構,縱軸表示產品族,上圖共有兩個產品族,分佈於三個不一樣的產品等級結構中。只要指明一個產品所處的產品族以及它所屬的等級結構,就能夠惟一的肯定這個產品。
上面所給出的三個不一樣的等級結構具備平行的結構。所以,若是採用工廠方法模式,就勢必要使用三個獨立的工廠等級結構來對付這三個產品等級結構。因爲這三個產品等級結構的類似性,會致使三個平行的工廠等級結構。隨着產品等級結構的數目的增長,工廠方法模式所給出的工廠等級結構的數目也會隨之增長。以下圖:
那麼,是否可使用同一個工廠等級結構來對付這些相同或者極爲類似的產品等級結構呢?固然能夠的,並且這就是抽象工廠模式的好處。同一個工廠等級結構負責三個不一樣產品等級結構中的產品對象的建立。
能夠看出,一個工廠等級結構能夠建立出分屬於不一樣產品等級結構的一個產品族中的全部對象。顯然,這時候抽象工廠模式比簡單工廠模式、工廠方法模式更有效率。對應於每個產品族都有一個具體工廠。而每個具體工廠負責建立屬於同一個產品族,可是分屬於不一樣等級結構的產品。
抽象工廠模式是對象的建立模式,它是工廠方法模式的進一步推廣。
假設一個子系統須要一些產品對象,而這些產品又屬於一個以上的產品等級結構。那麼爲了將消費這些產品對象的責任和建立這些產品對象的責任分割開來,能夠引進抽象工廠模式。這樣的話,消費產品的一方不須要直接參與產品的建立工做,而只須要向一個公用的工廠接口請求所須要的產品。
經過使用抽象工廠模式,能夠處理具備相同(或者類似)等級結構中的多個產品族中的產品對象的建立問題。以下圖所示:
因爲這兩個產品族的等級結構相同,所以使用同一個工廠族也能夠處理這兩個產品族的建立問題,這就是抽象工廠模式。
根據產品角色的結構圖,就不難給出工廠角色的結構設計圖。
能夠看出,每個工廠角色都有兩個工廠方法,分別負責建立分屬不一樣產品等級結構的產品對象。
抽象工廠的功能是爲一系列相關對象或相互依賴的對象建立一個接口。必定要注意,這個接口內的方法不是任意堆砌的,而是一系列相關或相互依賴的方法。好比上面例子中的主板和CPU,都是爲了組裝一臺電腦的相關對象。不一樣的裝機方案,表明一種具體的電腦系列。
因爲抽象工廠定義的一系列對象一般是相關或相互依賴的,這些產品對象就構成了一個產品族,也就是抽象工廠定義了一個產品族。
這就帶來很是大的靈活性,切換產品族的時候,只要提供不一樣的抽象工廠實現就能夠了,也就是說如今是以一個產品族做爲一個總體被切換。
1.一個系統不該當依賴於產品類實例如何被建立、組合和表達的細節,這對於全部形態的工廠模式都是重要的。
2.這個系統的產品有多於一個的產品族,而系統只消費其中某一族的產品。
3.同屬於同一個產品族的產品是在一塊兒使用的,這一約束必須在系統的設計中體現出來。(好比:Intel主板必須使用Intel CPU、Intel芯片組)
4.系統提供一個產品類的庫,全部的產品以一樣的接口出現,從而使客戶端不依賴於實現。
抽象工廠模式的起源或者最先的應用,是用於建立分屬於不一樣操做系統的視窗構建。好比:命令按鍵(Button)與文字框(Text)都是視窗構建,在UNIX操做系統的視窗環境和Windows操做系統的視窗環境中,這兩個構建有不一樣的本地實現,它們的細節有所不一樣。
在每個操做系統中,都有一個視窗構建組成的構建家族。在這裏就是Button和Text組成的產品族。而每個視窗構件都構成本身的等級結構,由一個抽象角色給出抽象的功能描述,而由具體子類給出不一樣操做系統下的具體實現。
客戶端使用抽象工廠來建立須要的對象,而客戶端根本就不知道具體的實現是誰,客戶端只是面向產品的接口編程而已。也就是說,客戶端從具體的產品實現中解耦。
由於一個具體的工廠實現表明的是一個產品族,好比上面例子的從Intel系列到AMD系列只須要切換一下具體工廠。
若是須要給整個產品族添加一個新的產品,那麼就須要修改抽象工廠,這樣就會致使修改全部的工廠實現類。
class AbstractFactory(object): computer_name = '' def createCpu(self): pass def createMainboard(self): pass class IntelFactory(AbstractFactory): computer_name = 'Intel I7-series computer ' def createCpu(self): return IntelCpu('I7-6500') def createMainboard(self): return IntelMainBoard('Intel-6000') class AmdFactory(AbstractFactory): computer_name = 'Amd 4 computer ' def createCpu(self): return AmdCpu('amd444') def createMainboard(self): return AmdMainBoard('AMD-4000') class AbstractCpu(object): series_name = '' instructions = '' arch='' class IntelCpu(AbstractCpu): def __init__(self,series): self.series_name = series class IntelCpu(AbstractCpu): def __init__(self,series): self.series_name = series class AmdCpu(AbstractCpu): def __init__(self,series): self.series_name = series class AbstractMainboard(object): series_name = '' class IntelMainBoard(AbstractMainboard): def __init__(self,series): self.series_name = series class AmdMainBoard(AbstractMainboard): def __init__(self,series): self.series_name = series class ComputerEngineer(object): def makeComputer(self,computer_obj): self.prepareHardwares(computer_obj) def prepareHardwares(self,computer_obj): self.cpu = computer_obj.createCpu() self.mainboard = computer_obj.createMainboard() info = '''------- computer [%s] info: cpu: %s mainboard: %s -------- End -------- '''% (computer_obj.computer_name,self.cpu.series_name,self.mainboard.series_name) print(info) if __name__ == "__main__": engineer = ComputerEngineer() computer_factory = IntelFactory() engineer.makeComputer(computer_factory) computer_factory2 = AmdFactory() engineer.makeComputer(computer_factory2)
意圖:
將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示。
適用性:
當建立複雜對象的算法應該獨立於該對象的組成部分以及它們的裝配方式時。
當構造過程必須容許被構造的對象有不一樣的表示時。
#建造者模式 #相關模式:思路和模板方法模式很像,模板方法是封裝算法流程,對某些細節,提供接口由子類修改,建造者模式更爲高層一點,將全部細節都交由子類實現。 # 建造者模式:將一個複雜對象的構建與他的表示分離,使得一樣的構建過程能夠建立不一樣的表示。 # 基本思想 # 某類產品的構建由不少複雜組件組成; # 這些組件中的某些細節不一樣,構建出的產品表象會略有不一樣; # 經過一個指揮者按照產品的建立步驟來一步步執行產品的建立; # 當須要建立不一樣的產品時,只須要派生一個具體的建造者,重寫相應的組件構建方法便可。 def printInfo(info): print(info) #建造者基類 class PersonBuilder(): def BuildHead(self): pass def BuildBody(self): pass def BuildArm(self): pass def BuildLeg(self): pass #胖子 class PersonFatBuilder(PersonBuilder): type = '胖子' def BuildHead(self): printInfo("構建%s的頭" % self.type) def BuildBody(self): printInfo("構建%s的身體" % self.type) def BuildArm(self): printInfo("構建%s的手" % self.type) def BuildLeg(self): printInfo("構建%s的腳" % self.type) #瘦子 class PersonThinBuilder(PersonBuilder): type = '瘦子' def BuildHead(self): printInfo("構建%s的頭" % self.type) def BuildBody(self): printInfo("構建%s的身體" % self.type) def BuildArm(self): printInfo("構建%s的手" % self.type) def BuildLeg(self): printInfo("構建%s的腳" % self.type) #指揮者 class PersonDirector(): pb = None; def __init__(self, pb): self.pb = pb def CreatePereson(self): self.pb.BuildHead() self.pb.BuildBody() self.pb.BuildArm() self.pb.BuildLeg() def clientUI(): pb = PersonThinBuilder() pd = PersonDirector(pb) pd.CreatePereson() pb = PersonFatBuilder() pd = PersonDirector(pb) pd.CreatePereson() return if __name__ == '__main__': clientUI();
意圖:
保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
適用性:
當類只能有一個實例並且客戶能夠從一個衆所周知的訪問點訪問它時。
當這個惟一實例應該是經過子類化可擴展的,而且客戶應該無需更改代碼就能使用一個擴展的實例時。
#實現__new__方法 #並在將一個類的實例綁定到類變量_instance上, #若是cls._instance爲None說明該類尚未實例化過,實例化該類,並返回 #若是cls._instance不爲None,直接返回cls._instance import time import threading class Singleton(object): instance = None lock = threading.RLock() # 實例化鎖對象 def __init__(self): self.age = 19 def __new__(cls, *args, **kwargs): if cls.instance: # 優化代碼,當已經建立過單例實例以後就不用再建立鎖了,由於建立和釋放鎖也是要消耗資源的 return cls.instance with cls.lock: # 加鎖 if not cls.instance: obj = object.__new__(cls) time.sleep(0.5) # 增長io cls.instance = obj return cls.instance def task(i): obj = Singleton() print(i,obj) for i in range(10): t = threading.Thread(target=task,args=(i,)) t.start() time.sleep(100) obj = Singleton() # 再次想要建立單例實例,直接返回已經建立好的單例對象,而不用再建立鎖了
意圖
將一個類的接口轉換成客戶但願的另一個接口。Adapter 模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做。
適用性:你想使用一個已經存在的類,而它的接口不符合你的需求。
你想建立一個能夠複用的類,該類能夠與其餘不相關的類或不可預見的類(即那些接口可能不必定兼容的類)協同工做
#適配器模式 # 將一個類的接口轉換成客戶但願的另一個接口。使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做。 # 應用場景:但願複用一些現存的類,可是接口又與複用環境要求不一致。 def printInfo(info): print(info) #球員類 class Player(): name = '' def __init__(self,name): self.name = name def Attack(self,name): pass def Defense(self): pass #前鋒 class Forwards(Player): def __init__(self,name): Player.__init__(self,name) def Attack(self): printInfo("前鋒%s 進攻" % self.name) def Defense(self,name): printInfo("前鋒%s 防守" % self.name) #中鋒(目標類) class Center(Player): def __init__(self,name): Player.__init__(self,name) def Attack(self): printInfo("中鋒%s 進攻" % self.name) def Defense(self): printInfo("中鋒%s 防守" % self.name) #後衛 class Guards(Player): def __init__(self,name): Player.__init__(self,name) def Attack(self): printInfo("後衛%s 進攻" % self.name) def Defense(self): printInfo("後衛%s 防守" % self.name) #外籍中鋒(待適配類) #中鋒 class ForeignCenter(Player): name = '' def __init__(self,name): Player.__init__(self,name) def ForeignAttack(self): printInfo("外籍中鋒%s 進攻" % self.name) def ForeignDefense(self): printInfo("外籍中鋒%s 防守" % self.name) #翻譯(適配類) class Translator(Player): foreignCenter = None def __init__(self,name): self.foreignCenter = ForeignCenter(name) def Attack(self): self.foreignCenter.ForeignAttack() def Defense(self): self.foreignCenter.ForeignDefense() def clientUI(): b = Forwards('巴蒂爾') m = Guards('姚明') ym = Translator('麥克格雷迪') b.Attack() m.Defense() ym.Attack() ym.Defense() return if __name__ == '__main__': clientUI()
參考:http://www.cnblogs.com/houleixx/archive/2008/02/23/1078877.html
生活中的一個例子:
就拿汽車在路上行駛的來講。即有小汽車又有公共汽車,它們都不但能在市區中的公路上行駛,也能在高速公路上行駛。這你會發現,對於交通工具(汽車)有不一樣的類型,然而它們所行駛的環境(路)也在變化,在軟件系統中就要適應兩個方面的變化?怎樣實現才能應對這種變化呢?
概述:
在軟件系統中,某些類型因爲自身的邏輯,它具備兩個或多個維度的變化,那麼如何應對這種「多維度的變化」?如何利用面嚮對象的技術來使得該類型可以輕鬆的沿着多個方向進行變化,而又不引入額外的複雜度?這就要使用Bridge模式。
意圖:
將抽象部分與實現部分分離,使它們均可以獨立的變化。
——《設計模式》GOF
效果及實現要點:
1.Bridge模式使用「對象間的組合關係」解耦了抽象和實現之間固有的綁定關係,使得抽象和實現能夠沿着各自的維度來變化。
2.所謂抽象和實現沿着各自維度的變化,即「子類化」它們,獲得各個子類以後,即可以任意它們,從而得到不一樣路上的不一樣汽車。
3.Bridge模式有時候相似於多繼承方案,可是多繼承方案每每違背了類的單一職責原則(即一個類只有一個變化的緣由),複用性比較差。Bridge模式是比多繼承方案更好的解決方法。
4.Bridge模式的應用通常在「兩個很是強的變化維度」,有時候即便有兩個變化的維度,可是某個方向的變化維度並不劇烈——換言之兩個變化不會致使縱橫交錯的結果,並不必定要使用Bridge模式。
適用性:
在如下的狀況下應當使用橋樑模式:
1.若是一個系統須要在構件的抽象化角色和具體化角色之間增長更多的靈活性,避免在兩個層次之間創建靜態的聯繫。
2.設計要求實現化角色的任何改變不該當影響客戶端,或者說實現化角色的改變對客戶端是徹底透明的。
3.一個構件有多於一個的抽象化角色和實現化角色,系統須要它們之間進行動態耦合。
4.雖然在系統中使用繼承是沒有問題的,可是因爲抽象化角色和具體化角色須要獨立變化,設計要求須要獨立管理這二者。
總結:
Bridge模式是一個很是有用的模式,也很是複雜,它很好的符合了開放-封閉原則和優先使用對象,而不是繼承這兩個面向對象原則
class AbstractRoad(object): '''公路基類''' car = None class AbstractCar(object): '''車輛基類''' def run(self): pass class Street(AbstractRoad): '''市區街道''' def run(self): self.car.run() print("在市區街道上行駛") class SpeedWay(AbstractRoad): '''高速公路''' def run(self): self.car.run() print("在高速公路上行駛") class Car(AbstractCar): '''小汽車''' def run(self): print("小汽車在") class Bus(AbstractCar): '''公共汽車''' def run(self): print("公共汽車在") if __name__ == "__main__": #小汽車在高速上行駛 road1 = SpeedWay() road1.car = Car() road1.run() # road2 = SpeedWay() road2.car = Bus() road2.run()
應用設計模式:
橋接模式(Bridge)來作(多維度變化);
結合上面的例子,增長一個維度"人",不一樣的人開着不一樣的汽車在不一樣的路上行駛(三個維度);
結合上面增長一個類"人",並從新調用.
代碼實現:
class AbstractRoad(object): '''公路基類''' car = None class AbstractCar(object): '''車輛基類''' def run(self): pass class People(object): pass class Street(AbstractRoad): '''市區街道''' def run(self): self.car.run() print("在市區街道上行駛") class SpeedWay(AbstractRoad): '''高速公路''' def run(self): self.car.run() print("在高速公路上行駛") class Car(AbstractCar): '''小汽車''' def run(self): print("小汽車在") class Bus(AbstractCar): '''公共汽車''' road = None def run(self): print("公共汽車在") #加上人 class Man(People): def drive(self): print("男人開着") self.road.run() #加上人 class Woman(People): def drive(self): print("女人開着") self.road.run() if __name__ == "__main__": #小汽車在高速上行駛 road1 = SpeedWay() road1.car = Car() road1.run() # road2 = SpeedWay() road2.car = Bus() road2.run() #人開車 road3 = Street() road3.car = Car() p1 = Man() p1.road = road3 p1.drive()
意圖:
將對象組合成樹形結構以表示「部分-總體」的層次結構。C o m p o s i t e 使得用戶對單個對象和組合對象的使用具備一致性。
適用性:你想表示對象的部分-總體層次結構。
你但願用戶忽略組合對象與單個對象的不一樣,用戶將統一地使用組合結構中的全部對象。
# 應用組合模式的會員卡消費 # # 那麼咱們就根據咱們會員卡的消費,來模擬一下組合模式的實現吧!let's go! # # 首先: # # 1.咱們的部件有,總店,分店,加盟店! # # 2.咱們的部件共有的行爲是:刷會員卡 # # 3.部件之間的層次關係,也就是店面的層次關係是,總店下有分店、分店下能夠擁有加盟店。 # # 有了咱們這幾個必要條件後,個人要求就是目前店面搞活動當我在總店刷卡後,就能夠累積至關於在全部下級店面刷卡的積分總額,設計的代碼以下 class Store(object): '''店面基類''' #添加店面 def add(self,store): pass #刪除店面 def remove(self,store): pass def pay_by_card(self): pass class BranchStore(Store): def __init__(self,name): self.name = name self.my_store_list = [] def pay_by_card(self): print("店面[%s]的積分已累加進該會員卡" %self.name) for s in self.my_store_list: s.pay_by_card() #添加店面 def add(self,store): self.my_store_list.append(store) #刪除店面 def remove(self,store): self.my_store_list.remove(store) class JoinStore(Store): '''加盟店''' def __init__(self,name): self.name = name def pay_by_card(self): print("店面[%s]的積分已累加進該會員卡" %self.name) def add(self,store): print("無添加子店權限") def remove(self,store): print("無刪除子店權限") if __name__ == "__main__": store = BranchStore("朝陽總店") branch = BranchStore("海濱分店") join_branch = JoinStore("昌平加盟1店") join_branch2 = JoinStore("昌平加盟2店") branch.add(join_branch) branch.add(join_branch2) store.add(branch) store.pay_by_card() print(store.my_store_list) # 這樣在累積全部子店面積分的時候,就不須要去關心子店面的個數了,也不用關係是不是葉子節點仍是組合節點了,也就是說無論是總店刷卡,仍是加盟店刷卡,均可以正確有效的計算出活動積分。 # # 什麼狀況下使用組合模式 # # 引用大話設計模式的片斷:「當發現需求中是體現部分與總體層次結構時,以及你但願用戶能夠忽略組合對象與單個對象的不一樣,統一地使用組合結構中的全部對象時,就應該考慮組合模式了。」 #
意圖:
爲子系統中的一組接口提供一個一致的界面,Facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。
適用性:
當你要爲一個複雜子系統提供一個簡單接口時。子系統每每由於不斷演化而變得愈來愈複雜。大多數模式使用時都會產生更多更小的類。這使得子系統更具可重用性,也更容易對子系統進行定製,但這也給那些不須要定製子系統的用戶帶來一些使用上的困難。Facade 能夠提供一個簡單的缺省視圖,這一視圖對大多數用戶來講已經足夠,而那些須要更多的可定製性的用戶能夠越過facade層。
客戶程序與抽象類的實現部分之間存在着很大的依賴性。引入facade 將這個子系統與客戶以及其餘的子系統分離,能夠提升子系統的獨立性和可移植性。
當你須要構建一個層次結構的子系統時,使用facade模式定義子系統中每層的入口點。若是子系統之間是相互依賴的,你可讓它們僅經過facade進行通信,從而簡化了它們之間的依賴關係。
#外觀模式(Facade),爲子系統中的一組接口提供一個一致的界面,定義一個高層接口,這個接口使得這一子系統更加容易使用。 # 在如下狀況下能夠考慮使用外觀模式: # (1)設計初期階段,應該有意識的將不一樣層分離,層與層之間創建外觀模式。 # (2) 開發階段,子系統愈來愈複雜,增長外觀模式提供一個簡單的調用接口。 # (3) 維護一個大型遺留系統的時候,可能這個系統已經很是難以維護和擴展,但又包含很是重要的功能,爲其開發一個外觀類,以便新系統與其交互。 # 優勢編輯 # (1)實現了子系統與客戶端之間的鬆耦合關係。 # (2)客戶端屏蔽了子系統組件,減小了客戶端所需處理的對象數目,並使得子系統使用起來更加容易。 def printInfo(info): print(info) class Stock(): name = '股票1' def buy(self): printInfo('買 '+self.name) def sell(self): printInfo('賣 '+self.name) class ETF(): name = '指數型基金' def buy(self): printInfo('買 '+self.name) def sell(self): printInfo('賣 '+self.name) class Future(): name = '期貨' def buy(self): printInfo('買 '+self.name) def sell(self): printInfo('賣 '+self.name) class NationDebt(): name = '國債' def buy(self): printInfo('買 '+self.name) def sell(self): printInfo('賣 '+self.name) class Option(): name = '權證' def buy(self): printInfo('買 '+self.name) def sell(self): printInfo('賣 '+self.name) #基金 class Fund(): def __init__(self): self.stock = Stock() self.etf = ETF() self.future = Future() self.debt = NationDebt() self.option = Option() def buyFund(self): self.stock.buy() self.etf.buy() self.debt.buy() self.future.buy() self.option.buy() def sellFund(self): self.stock.sell() self.etf.sell() self.future.sell() self.debt.sell() self.option.sell() def clientUI(): myFund = Fund() myFund.buyFund() myFund.sellFund() return if __name__ == '__main__': clientUI();
意圖:
運用共享技術有效地支持大量細粒度的對象。
適用性:
一個應用程序使用了大量的對象。
徹底因爲使用大量的對象,形成很大的存儲開銷。
對象的大多數狀態均可變爲外部狀態。
若是刪除對象的外部狀態,那麼能夠用相對較少的共享對象取代不少組對象。
應用程序不依賴於對象標識。因爲Flyweight 對象能夠被共享,對於概念上明顯有別的對象,標識測試將返回真值。
# Flyweight模式,顧名思義,就是共享元數據 # 在咱們面向對象設計過程當中,咱們經常會面臨着對象實例過多的問題,若是對象實例過多這將是咱們系統性能提升的一個瓶頸。 # 假設咱們要設計一個星空場景,如今咱們須要實例星星對象,咱們能夠實例每一顆星星,但隨着咱們實例星星對象增多整個場景就愈來愈慢了, # 若是你實例了1000+顆星星要你去維護,這但是一個吃力不討好的工做。咱們必須找到一個合適的方法解決以上問題,這就是今天要介紹的享元模式(Flyweight)。 # 享元模式(Flyweight):運用共享的技術有效地支持大量細粒度的對象。 # # 抽象享元角色(Flyweight):此角色是全部的具體享元類的超類,爲這些類規定出須要實現的公共接口或抽象類。那些須要外部狀態(External State)的操做能夠經過方法的參數傳入。抽象享元的接口使得享元變得可能,可是並不強制子類實行共享,所以並不是全部的享元對象都是能夠共享的。 # # 具體享元(ConcreteFlyweight)角色:實現抽象享元角色所規定的接口。若是有內部狀態的話,必須負責爲內部狀態提供存儲空間。享元對象的內部狀態必須與對象所處的周圍環境無關,從而使得享元對象能夠在系統內共享。有時候具體享元角色又叫作單純具體享元角色,由於複合享元角色是由單純具體享元角色經過複合而成的。 # # 複合享元(UnsharableFlyweight)角色:複合享元角色所表明的對象是不能夠共享的,可是一個複合享元對象能夠分解成爲多個自己是單純享元對象的組合。複合享元角色又稱作不可共享的享元對象。這個角色通常不多使用。 # # 享元工廠(FlyweightFactoiy)角色:本角色負責建立和管理享元角色。本角色必須保證享元對象能夠被系統適當地共享。當一個客戶端對象請求一個享元對象的時候,享元工廠角色須要檢查系統中是否已經有一個符合要求的享元對象,若是已經有了,享元工廠角色就應當提供這個已有的享元對象;若是系統中沒有一個適當的享元對象的話,享元工廠角色就應當建立一個新的合適的享元對象。 # # 客戶端(Client)角色:本角色還須要自行存儲全部享元對象的外部狀態。 # # 內部狀態與外部狀態:在享元對象內部而且不會隨着環境改變而改變的共享部分,能夠稱之爲享元對象的內部狀態,反之隨着環境改變而改變的,不可共享的狀態稱之爲外部狀態。 class FlyweightBase(object): _instances = dict() def __init__(self,*args,**kwargs): #繼承的子類必須初始化 raise NotImplementedError def __new__(cls, *args, **kwargs): #print(cls._instances,type(cls)) return cls._instances.setdefault( (cls,args,tuple(kwargs.items())), super(FlyweightBase,cls).__new__(cls) ) def test_data(self): pass class Spam(FlyweightBase): '''精子類''' def __init__(self,a,b): self.a = a self.b = b def test_data(self): print("精子準備好了",self.a,self.b) class Egg(FlyweightBase): '''卵類''' def __init__(self,x,y): self.x = x self.y = y def test_data(self): print("卵子準備好了",self.x,self.y) spam1 = Spam(1,'abc') spam2 = Spam(1,'abc') spam3 = Spam(3,'DEF') egg1 = Egg(1,'abc') #egg2 = Egg(4,'abc') assert spam1 is spam2 assert egg1 is not spam1 print(id(spam1),id(spam2)) spam2.test_data() egg1.test_data() print(egg1._instances) print(egg1._instances.keys())
意圖:爲其餘對象提供一種代理以控制對這個對象的訪問。
主要解決:在直接訪問對象時帶來的問題,好比說:要訪問的對象在遠程的機器上。在面向對象系統中,有些對象因爲某些緣由(好比對象建立開銷很大,或者某些操做須要安全控制,或者須要進程外的訪問),直接訪問會給使用者或者系統結構帶來不少麻煩,咱們能夠在訪問此對象時加上一個對此對象的訪問層。
什麼時候使用:想在訪問一個類時作一些控制。
如何解決:增長中間層。
關鍵代碼:實現與被代理類組合。
應用實例: 一、Windows 裏面的快捷方式。 二、豬八戒去找高翠蘭結果是孫悟空變的,能夠這樣理解:把高翠蘭的外貌抽象出來,高翠蘭本人和孫悟空都實現了這個接口,豬八戒訪問高翠蘭的時候看不出來這個是孫悟空,因此說孫悟空是高翠蘭代理類。 三、買火車票不必定在火車站買,也能夠去代售點。 四、一張支票或銀行存單是帳戶中資金的代理。支票在市場交易中用來代替現金,並提供對簽發人帳號上資金的控制。 五、spring aop。
優勢: 一、職責清晰。 二、高擴展性。 三、智能化。
缺點: 一、因爲在客戶端和真實主題之間增長了代理對象,所以有些類型的代理模式可能會形成請求的處理速度變慢。 二、實現代理模式須要額外的工做,有些代理模式的實現很是複雜。
使用場景:按職責來劃分,一般有如下使用場景: 一、遠程代理。 二、虛擬代理。 三、Copy-on-Write 代理。 四、保護(Protect or Access)代理。 五、Cache代理。 六、防火牆(Firewall)代理。 七、同步化(Synchronization)代理。 八、智能引用(Smart Reference)代理。
# 代理模式 # 應用特性:須要在通訊雙方中間須要一些特殊的中間操做時引用,多加一箇中間控制層。 # 結構特性:創建一箇中間類,建立一個對象,接收一個對象,而後把二者聯通起來 class sender_base: def __init__(self): pass def send_something(self, something): pass class send_class(sender_base): def __init__(self, receiver): self.receiver = receiver def send_something(self, something): print("SEND " + something + ' TO ' + self.receiver.name) class agent_class(sender_base): def __init__(self, receiver): self.send_obj = send_class(receiver) def send_something(self, something): self.send_obj.send_something(something) class receive_class: def __init__(self, someone): self.name = someone if '__main__' == __name__: receiver = receive_class('Alex') agent = agent_class(receiver) agent.send_something('agentinfo') print(receiver.__class__ ) print(agent.__class__ )
在模板模式(Template Pattern)中,一個抽象類公開定義了執行它的方法的方式/模板。它的子類能夠按須要重寫方法實現,但調用將以抽象類中定義的方式進行。這種類型的設計模式屬於行爲型模式。
意圖:定義一個操做中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟。
主要解決:一些方法通用,卻在每個子類都從新寫了這一方法。
什麼時候使用:有一些通用的方法。
如何解決:將這些通用算法抽象出來。
關鍵代碼:在抽象類實現,其餘步驟在子類實現。
應用實例: 一、在造房子的時候,地基、走線、水管都同樣,只有在建築的後期纔有加壁櫥加柵欄等差別。 二、西遊記裏面菩薩定好的 81 難,這就是一個頂層的邏輯骨架。 三、Spirng 中對 Hibernate 的支持,將一些已經定好的方法封裝起來,好比開啓事務、獲取 Session、關閉 Session 等,程序員不重複寫那些已經規範好的代碼,直接丟一個實體就能夠保存。
優勢: 一、封裝不變部分,擴展可變部分。 二、提取公共代碼,便於維護。 三、行爲由父類控制,子類實現。
缺點:每個不一樣的實現都須要一個子類來實現,致使類的個數增長,使得系統更加龐大。
使用場景: 一、有多個子類共有的方法,且邏輯相同。 二、重要的、複雜的方法,能夠考慮做爲模板方法。
# 模板方法模式概述 # 在現實生活中,不少事情都包含幾個實現步驟,例如請客吃飯,不管吃什麼,通常都包含點單、吃東西、買單等幾個步驟,一般狀況下這幾個步驟的次序是:點單 --> 吃東西 --> 買單。在這三個步驟中,點單和買單大同小異,最大的區別在於第二步——吃什麼?吃麪條和吃滿漢全席可大不相同,如圖1所示: # # 圖1 請客吃飯示意圖 # 在軟件開發中,有時也會遇到相似的狀況,某個方法的實現須要多個步驟(相似「請客」),其中有些步驟是固定的(相似「點單」和「買單」),而有些步驟並不固定,存在可變性(相似「吃東西」)。爲了提升代碼的複用性和系統的靈活性,可使用一種稱之爲模板方法模式的設計模式來對這類狀況進行設計,在模板方法模式中,將實現功能的每個步驟所對應的方法稱爲基本方法(例如「點單」、「吃東西」和「買單」),而調用這些基本方法同時定義基本方法的執行次序的方法稱爲模板方法(例如「請客」)。在模板方法模式中,能夠將相同的代碼放在父類中,例如將模板方法「請客」以及基本方法「點單」和「買單」的實現放在父類中,而對於基本方法「吃東西」,在父類中只作一個聲明,將其具體實現放在不一樣的子類中,在一個子類中提供「吃麪條」的實現,而另外一個子類提供「吃滿漢全席」的實現。經過使用模板方法模式,一方面提升了代碼的複用性,另外一方面還能夠利用面向對象的多態性,在運行時選擇一種具體子類,實現完整的「請客」方法,提升系統的靈活性和可擴展性。 # 模板方法模式定義以下: # 模板方法模式:定義一個操做中算法的框架,而將一些步驟延遲到子類中。模板方法模式使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟。 # # Template Method Pattern: Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure. # 模板方法模式是一種基於繼承的代碼複用技術,它是一種類行爲型模式。 # 模板方法模式是結構最簡單的行爲型設計模式,在其結構中只存在父類與子類之間的繼承關係。經過使用模板方法模式,能夠將一些複雜流程的實現步驟封裝在一系列基本方法中,在抽象父類中提供一個稱之爲模板方法的方法來定義這些基本方法的執行次序,而經過其子類來覆蓋某些步驟,從而使得相同的算法框架能夠有不一樣的執行結果。模板方法模式提供了一個模板方法來定義算法框架,而某些具體步驟的實現能夠在其子類中完成。 # class Register(object): '''用戶註冊接口''' def register(self): pass def login(self): pass def auth(self): self.register() self.login() class RegisterByQQ(Register): '''qq註冊''' def register(self): print("---用qq註冊-----") def login(self): print('----用qq登陸-----') class RegisterByWeiChat(Register): '''微信註冊''' def register(self): print("---用微信註冊-----") def login(self): print('----用微信登陸-----') if __name__ == "__main__": register1 = RegisterByQQ() register1.login() register2 = RegisterByWeiChat() register2.login()
意圖:
使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。
適用性:
有多個的對象能夠處理一個請求,哪一個對象處理該請求運行時刻自動肯定。
你想在不明確指定接收者的狀況下,向多個對象中的一個提交一個請求。
可處理一個請求的對象集合應被動態指定。
# 職責鏈模式(Chain of Responsibility):使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。 # 適用場景: # 一、有多個的對象能夠處理一個請求,哪一個對象處理該請求運行時刻自動肯定; # 二、在不明確指定接收者的狀況下,向多個對象中的一個提交一個請求; # 三、處理一個請求的對象集合應被動態指定。 class BaseHandler(object): '''處理基類''' def successor(self,successor): #與下一個責任者關聯 self._successor = successor class RequestHandlerL1(BaseHandler): '''第一級請求處理者''' name = "TeamLeader" def handle(self,request): if request < 500 : print("審批者[%s],請求金額[%s],審批結果[審批經過]"%(self.name,request)) else: print("\033[31;1m[%s]無權審批,交給下一個審批者\033[0m" %self.name) self._successor.handle(request) class RequestHandlerL2(BaseHandler): '''第二級請求處理者''' name = "DeptManager" def handle(self,request): if request < 5000 : print("審批者[%s],請求金額[%s],審批結果[審批經過]"%(self.name,request)) else: print("\033[31;1m[%s]無權審批,交給下一個審批者\033[0m" %self.name) self._successor.handle(request) class RequestHandlerL3(BaseHandler): '''第三級請求處理者''' name = "CEO" def handle(self,request): if request < 10000 : print("審批者[%s],請求金額[%s],審批結果[審批經過]"%(self.name,request)) else: print("\033[31;1m[%s]要太多錢了,不批\033[0m"%self.name) #self._successor.handle(request) class RequestAPI(object): h1 = RequestHandlerL1() h2 = RequestHandlerL2() h3 = RequestHandlerL3() h1.successor(h2) h2.successor(h3) def __init__(self,name,amount): self.name = name self.amount = amount def handle(self): '''統一請求接口''' self.h1.handle(self.amount) if __name__ == "__main__": r1 = RequestAPI("Alex",30000) r1.handle() print(r1.__dict__)
意圖:
定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時, 全部依賴於它的對象都獲得通知並被自動更新。
適用性:
當一個抽象模型有兩個方面, 其中一個方面依賴於另外一方面。將這兩者封裝在獨立的對象中以使它們能夠各自獨立地改變和複用。
當對一個對象的改變須要同時改變其它對象, 而不知道具體有多少對象有待改變。
當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之, 你不但願這些對象是緊密耦合的。
# 觀察者(Observer)模式又名發佈-訂閱(Publish/Subscribe)模式 # 當咱們但願一個對象的狀態發生變化,那麼依賴與它的全部對象都能相應變化(得到通知),那麼就能夠用到Observer模式, 其中的這些依賴對象就是觀察者的對象,那個要發生變化的對象就是所謂’觀察者’ class ObserverBase(object): '''觀察者基類''' def __init__(self): self._observerd_list = [] def attach(self,observe_subject): ''' 添加要觀察的對象 :param observe_subject: :return: ''' if observe_subject not in self._observerd_list: self._observerd_list.append(observe_subject) print("[%s]已經將[%s]加入觀察隊列..."%(self.name,observe_subject) ) def detach(self,observe_subject): ''' 解除觀察關係 :param observe_subject: :return: ''' try: self._observerd_list.remove(observe_subject) print("再也不觀察[%s]" %observe_subject) except ValueError: pass def notify(self): ''' 通知全部被觀察者 :return: ''' for objserver in self._observerd_list: objserver.update(self) class Observer(ObserverBase): '''觀察者類''' def __init__(self,name): super(Observer,self).__init__() self.name = name self._msg = '' @property def msg(self): ''' 當前情況 :return: ''' return self._msg @msg.setter def msg(self,content): self._msg = content self.notify() class GCDViewer(object): ''' 共軍被觀察者 ''' def update(self,observer_subject): print("共軍:收到[%s]消息[%s] "%(observer_subject.name,observer_subject.msg) ) class GMDViewer(object): ''' 國軍被觀察者 ''' def update(self,observer_subject): print("國軍:收到[%s]消息[%s] "%(observer_subject.name,observer_subject.msg) ) if __name__ == "__main__": observer1 = Observer("共軍放哨者") observer2 = Observer("國軍放哨者") gongjun1 = GCDViewer() guojun1 = GMDViewer() observer1.attach(gongjun1) observer1.attach(guojun1) observer2.attach(guojun1) observer1.msg = "\033[32;1m敵人來了...\033[0m" observer2.msg ="\033[31;1m前方發現敵人,請緊急撤離,不要告訴共軍\033[0m"
意圖:定義一系列的算法,把它們一個個封裝起來, 而且使它們可相互替換。
主要解決:在有多種算法類似的狀況下,使用 if...else 所帶來的複雜和難以維護。
什麼時候使用:一個系統有許多許多類,而區分它們的只是他們直接的行爲。
如何解決:將這些算法封裝成一個一個的類,任意地替換。
關鍵代碼:實現同一個接口。
應用實例: 一、諸葛亮的錦囊妙計,每個錦囊就是一個策略。 二、旅行的出遊方式,選擇騎自行車、坐汽車,每一種旅行方式都是一個策略。 三、JAVA AWT 中的 LayoutManager。
優勢: 一、算法能夠自由切換。 二、避免使用多重條件判斷。 三、擴展性良好。
缺點: 一、策略類會增多。 二、全部策略類都須要對外暴露。
使用場景: 一、若是在一個系統裏面有許多類,它們之間的區別僅在於它們的行爲,那麼使用策略模式能夠動態地讓一個對象在許多行爲中選擇一種行爲。 二、一個系統須要動態地在幾種算法中選擇一種。 三、若是一個對象有不少的行爲,若是不用恰當的模式,這些行爲就只好使用多重的條件選擇語句來實現。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
#_*_coding:utf-8_*_
__author__
=
'Alex Li'
class
TravelStrategy(
object
):
'''
出行策略
'''
def
travelAlgorithm(
self
):
pass
class
AirplaneStrategy(TravelStrategy):
def
travelAlgorithm(
self
):
print
(
"坐飛機出行...."
)
class
TrainStrategy(TravelStrategy):
def
travelAlgorithm(
self
):
print
(
"坐高鐵出行...."
)
class
CarStrategy(TravelStrategy):
def
travelAlgorithm(
self
):
print
(
"自駕出行...."
)
class
BicycleStrategy(TravelStrategy):
def
travelAlgorithm(
self
):
print
(
"騎車出行...."
)
class
TravelInterface(
object
):
def
__init__(
self
,travel_strategy):
self
.travel_strategy
=
travel_strategy
def
set_strategy(
self
,travel_strategy):
self
.travel_strategy
=
travel_strategy
def
travel(
self
):
return
self
.travel_strategy.travelAlgorithm()
#坐飛機
travel
=
TravelInterface(AirplaneStrategy())
travel.travel()
#改開車
travel.set_strategy(TrainStrategy())
travel.travel()
|