設計模式(Design pattern)是一套被反覆使用、多數人知曉的、通過分類編目的、代碼設計經驗的總結。使用設計模式是爲了可重用代碼、讓代碼更容易被他人理解、html
保證代碼可靠性。 毫無疑問,設計模式於己於他人於系統都是多贏的,設計模式使代碼編制真正工程化,設計模式是軟件工程的基石,如同大廈的一塊塊磚石同樣。python
項目中合理的運用設計模式能夠完美的解決不少問題,每種模式在如今中都有相應的原理來與之對應,每個模式描述了一個在咱們周圍不斷重複發生的問題,程序員
以及該問題的核心解決方案,這也是它能被普遍應用的緣由。算法
前面講過,社會化的分工愈來愈細,天然在軟件設計方面也是如此,所以對象的建立和對象的使用分開也就成爲了必然趨勢。由於對象的建立會消耗掉系統的不少資源,因此單獨對對象的建立進行研究,從而可以高效地建立對象就是建立型模式要探討的問題。這裏有6個具體的建立型模式可供研究,它們分別是:spring
簡單工廠模式(Simple Factory); 工廠方法模式(Factory Method); 抽象工廠模式(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)。
開閉原則就是說對擴展開放,對修改關閉。在程序須要進行拓展的時候,不能去修改原有的代碼,實現一個熱插拔的效果。因此一句話歸納就是:微信
爲了使程序的擴展性好,易於維護和升級。想要達到這樣的效果,咱們須要使用接口和抽象類,後面的具體設計中咱們會提到這點。架構
里氏代換原則(Liskov Substitution Principle LSP)面向對象設計的基本原則之一。 里氏代換原則中說,任何基類能夠出現的地方,子類必定能夠出現。
LSP是繼承複用的基石,只有當衍生類能夠替換掉基類,軟件單位的功能不受到影響時,基類才能真正被複用,而衍生類也可以在基類的基礎上增長新的行爲。
里氏代換原則是對「開-閉」原則的補充。實現「開-閉」原則的關鍵步驟就是抽象化。而基類與子類的繼承關係就是抽象化的具體實現,
因此里氏代換原則是對實現抽象化的具體步驟的規範。
這個是開閉原則的基礎,具體內容:是對接口編程,依賴於抽象而不依賴於具體。
這個原則的意思是:使用多個隔離的接口,比使用單個接口要好。仍是一個下降類之間的耦合度的意思,從這兒咱們看出,其實設計模式就是一個軟件的設計思想,
從大型軟件架構出發,爲了升級和維護方便。因此上文中屢次出現:下降依賴,下降耦合。
一個實體應當儘可能少的與其餘實體之間發生相互做用,使得系統功能模塊相對獨立。
原則是儘可能使用合成/聚合的方式,而不是使用繼承。
工廠模式(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()
每個模式都是針對必定問題的解決方案。抽象工廠模式與工廠方法模式的最大區別就在於,工廠方法模式針對的是一個產品等級結構;
而抽象工廠模式則須要面對多個產品等級結構。
抽象工廠模式是對象的建立模式,它是工廠方法模式的進一步推廣。
經過使用抽象工廠模式,能夠處理具備相同(或者類似)等級結構中的多個產品族中的產品對象的建立問題
因爲這兩個產品族的等級結構相同,所以使用同一個工廠族也能夠處理這兩個產品族的建立問題,這就是抽象工廠模式。
抽象工廠的功能是爲一系列相關對象或相互依賴的對象建立一個接口。必定要注意,這個接口內的方法不是任意堆砌的,而是一系列相關或相互依賴的方法。
好比上面例子中的主板和CPU,都是爲了組裝一臺電腦的相關對象。不一樣的裝機方案,表明一種具體的電腦系列。
1.一個系統不該當依賴於產品類實例如何被建立、組合和表達的細節,這對於全部形態的工廠模式都是重要的。
2.這個系統的產品有多於一個的產品族,而系統只消費其中某一族的產品。
3.同屬於同一個產品族的產品是在一塊兒使用的,這一約束必須在系統的設計中體現出來。(好比:Intel主板必須使用Intel CPU、Intel芯片組)
4.系統提供一個產品類的庫,全部的產品以一樣的接口出現,從而使客戶端不依賴於實現。
客戶端使用抽象工廠來建立須要的對象,而客戶端根本就不知道具體的實現是誰,客戶端只是面向產品的接口編程而已。也就是說,客戶端從具體的產品實現中解耦。
由於一個具體的工廠實現表明的是一個產品族,好比上面例子的從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 class Singleton(object): def __new__(cls, *args, **kwargs): if not hasattr(cls,'_instance'): orig = super(Singleton,cls) cls._instance = orig.__new__(cls) return cls._instance class MyClass(Singleton): def __init__(self,name): self.name = name a = MyClass("Alex") b = MyClass("Jack") print(a.name) print(b.name)
意圖 將一個類的接口轉換成客戶但願的另一個接口。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()
意圖: 將抽象部分與實現部分分離,使它們均可以獨立的變化。 ——《設計模式》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 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()
意圖: 將對象組合成樹形結構以表示「部分-總體」的層次結構。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。 優勢: 一、算法能夠自由切換。 二、避免使用多重條件判斷。 三、擴展性良好。 缺點: 一、策略類會增多。 二、全部策略類都須要對外暴露。 使用場景: 一、若是在一個系統裏面有許多類,它們之間的區別僅在於它們的行爲,那麼使用策略模式能夠動態地讓一個對象在許多行爲中選擇一種行爲。
二、一個系統須要動態地在幾種算法中選擇一種。 三、若是一個對象有不少的行爲,若是不用恰當的模式,這些行爲就只好使用多重的條件選擇語句來實現。
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()
更多詳見:http://www.cnblogs.com/alex3714/articles/5760582.html