什麼是設計模式php
設計模式(Design Pattern)是一套被反覆使用、多數人知曉的、通過分類的、代碼設計經驗的總結html
使用設計模式的目的java
爲了代碼可重用性、讓代碼更容易被他人理解、保證代碼可靠性。 設計模式使代碼編寫真正工程化;設計模式是軟件工程的基石脈絡,如同大廈的結構同樣node
設計模式六大原則python
1、開閉原則(Open Close Principle) 開閉原則:對擴展開放,對修改關閉。在程序須要進行擴展的時候,不能去修改或影響原有的代碼。 多使用接口和抽象類 2、里氏替換原則(Liskov Substitution Principle) 里氏替換:任何基類能夠出現的地方,子類必定能夠出現。 3、依賴倒置原則(Dependence Inversion Principle) 依賴倒置:針對接口編程,高層模塊不該該依賴底層模塊,兩者都應該依賴抽象。即不依賴與對接口的實現類,依賴抽象類。 4、接口隔離原則(Interface Segregation Principle) 接口隔離:客戶端不該該依賴它不須要的接口;一個類對另外一個類的依賴應該創建在最小的接口上,即細化接口功能。 使用多個隔離的接口,比使用單個龐大的接口要好。 5、單一職責原則(Single Responsibility Principle) 單一職責:一個類只負責一項職責。 單一職責原則是實現高內聚、低耦合的指導方針,它是最簡單但又最難運用的原則。 須要設計人員發現類的不一樣職責並將其分離,而發現類的多重職責須要設計人員具備較強的分析設計能力和相關實踐經驗 6、最少知識原則(Demeter Principle) 最少知識:又叫迪米特法則。一個對象應當對其餘對象有儘量少的瞭解。
下面將使用python編程語言實現GoF的23種設計模式,這些設計模式可分爲3大類:建立型、結構型和行爲型算法
建立型:
工廠方法模式 Factory Method Pattern
抽象工廠模式 Abstract Factory Pattern
建立者模式 Builder Pattern
原型模式 Prototype Pattern
單例模式 Singleton Pattern
結構型:
設配器模式 Adapter Pattern
橋接模式 Bridge Pattern
組合模式 Composite Pattern
外觀模式 Facade Pattern
享元模式 Flyweight Pattern
代理模式 Proxy Pattern
裝飾器模式 Decorator Pattern
行爲模式:
職責鏈模式 Chain of Responsibility Pattern
命令模式 Command Pattern
解釋器模式 Interpreter Pattern
迭代器模式 Iterator Pattern
中介者模式 Mediator Pattern
忘備錄模式 Memento Pattern
觀察者模式 Observer Pattern
狀態模式 State Pattern
策略模式 Strategy Pattern
模板方法模式 Template Method Pattern
訪問者模式 Visitor Pattern
設計模式詳解編程
1.工廠模式設計模式
在簡單工廠模式中,咱們在建立對象時不會對客戶端暴露建立邏輯,而且是經過使用一個共同的接口來指向新建立的對象.
優勢:客戶端不須要修改代碼。
缺點: 當須要增長新的運算類的時候,不只需新加運算類,還要修改工廠類,違反了開閉原則。
__author__ = 'Cq' class Shape(object): def draw(self): # 該方法若是沒有被重寫將會彈出異常 raise NotImplementedError class Circle(Shape): def draw(self): print("draw circle...") class Square(Shape): def draw(self): print("draw square...") class ShapeFactory(object): def create(self, shape): if shape == "circle": return Circle() elif shape == "square": return Square() else: return None def main(): fac = ShapeFactory() obj = fac.create("square") obj.draw() if "__main__" == __name__: main()
1 draw square...
在工廠模式中,對應每個產品都有相應的工廠
好處:增長一個運算類(例如N次方類),只須要增長運算類和相對應的工廠,兩個類,不須要修改工廠類。
缺點:增長運算類,會修改客戶端代碼,工廠方法只是把簡單工廠的內部邏輯判斷移到了客戶端進行。
__author__ = 'Cq' class AbstractProduct(object): def use(self): raise NotImplementedError class AbstractFactory(object): def create(self, owner): p = self.createProduct(owner) self.registerProduct(p) return p def createProduct(self, owner): raise NotImplementedError def registerProduct(self, p): raise NotImplementedError class IPhone(AbstractProduct): def __init__(self, name): self.__owner = name print("made %s's phone" % name) def use(self): print("%s use IPhone" % self.__owner) def getOwner(self): return self.__owner class Computer(AbstractProduct): def __init__(self, name): self.__owner = name print("made %s's computer" % name) def use(self): print("%s use computer" % self.__owner) def getOwner(self): return self.__owner class IPhoneFactory(AbstractFactory): def __init__(self): self.__owners = [] def createProduct(self, owner): return IPhone(owner) def registerProduct(self, p): self.__owners.append(p.getOwner()) def getOwners(self): return self.__owners class ComputerFactory(AbstractFactory): def __init__(self): self.__owners = [] def createProduct(self, owner): return Computer(owner) def registerProduct(self, p): self.__owners.append(p.getOwner()) def getOwners(self): return self.__owners def main(): fac_i = IPhoneFactory() fac_c = ComputerFactory() iphone1 = fac_i.create("alex") iphone2 = fac_i.create('seven') computer1 = fac_c.create("bob") computer2 = fac_c.create("tom") iphone1.use() iphone2.use() computer1.use() computer2.use() print(fac_i.getOwners()) print(fac_c.getOwners()) if "__main__" == __name__: main()
1 made alex's phone 2 made seven's phone 3 made bob's computer 4 made tom's computer 5 alex use IPhone 6 seven use IPhone 7 bob use computer 8 tom use computer 9 ['alex', 'seven'] 10 ['bob', 'tom']
2.抽象工廠模式緩存
抽象工廠模式與工廠方法模式的最大區別就在於,工廠方法模式針對的是一個產品;而抽象工廠模式則須要面對多個產品。 抽象工廠角色: AbstractProduct(抽象產品) 負責定義抽象工廠角色所生成的抽象零件和產品的接口 AbstractFactory(抽象工廠) 負責定義用於生成抽象產品的接口 Client(委託者) 僅會調用抽象產品和抽象角色的接口來進行工做,對於具體的零件、產品和工廠一無所知 ConcreteProduct(具體產品) 負責實現抽象產品的接口 ConcreteFactory(具體工廠) 負責實現抽象工廠的接口 在什麼狀況下應當使用抽象工廠模式 1.一個系統不依賴於產品類實例如何被建立、組合和表達的細節,這對於全部形態的工廠模式是很是重要的。 2.這個系統的產品有多於一個的產品,而系統只消費其中某一種的產品。 3.同屬於同一個產品的零件是在一塊兒使用的,這一約束必須在系統的設計中體現出來。(好比:Intel主板必須使用Intel CPU、Intel芯片組) 4.系統提供一個產品類的庫,全部的產品以一樣的接口出現,從而使客戶端不依賴於實現 優先:易於增長具體的工廠 缺點:難以增長新的零件
__author__ = 'Cq' class AbstractFactory(object): def __init__(self, name): self.fac_name = name def createCpu(self): raise NotImplementedError def createMainboard(self): raise NotImplementedError class IntelFactory(AbstractFactory): def __init__(self, name="Intel I7-series computer"): super(IntelFactory, self).__init__(name) def createCpu(self): return IntelCpu('I7-6500') def createMainboard(self): return IntelMainBoard('Intel-6000') class AmdFactory(AbstractFactory): def __init__(self, name="Amd 4 computer"): super(AmdFactory, self).__init__(name) def createCpu(self): return AmdCpu('amd444') def createMainboard(self): return AmdMainBoard('AMD-4000') class AbstractCpu(object): def __init__(self, name, instructions="", arch=""): self.series_name = name self.instructions = instructions self.arch = arch class IntelCpu(AbstractCpu): def __init__(self, series): super(IntelCpu, self).__init__(series) class AmdCpu(AbstractCpu): def __init__(self, series): super(AmdCpu, self).__init__(series) class AbstractMainboard(object): def __init__(self, name): self.series_name = name class IntelMainBoard(AbstractMainboard): def __init__(self, series): super(IntelMainBoard, self).__init__(series) class AmdMainBoard(AbstractMainboard): def __init__(self, series): super(AmdMainBoard, self).__init__(series) class ComputerEngineer(object): def __init__(self): self.cpu = None self.mainboard = None def makeComputer(self, factory_obj): self.prepareHardwares(factory_obj) def prepareHardwares(self, factory_obj): self.cpu = factory_obj.createCpu() self.mainboard = factory_obj.createMainboard() info = '''------- computer [%s] info: cpu: %s mainboard: %s -------- End -------- ''' % (factory_obj.fac_name, self.cpu.series_name, self.mainboard.series_name) print(info) def main(): engineer = ComputerEngineer() intel_computer = IntelFactory() engineer.makeComputer(intel_computer) amd_computer = AmdFactory() engineer.makeComputer(amd_computer) if "__main__" == __name__: main()
1 ------- computer [Intel I7-series computer] info: 2 3 cpu: I7-6500 4 mainboard: Intel-6000 5 6 -------- End -------- 7 8 9 ------- computer [Amd 4 computer] info: 10 11 cpu: amd444 12 mainboard: AMD-4000 13 14 -------- End --------
3.建立者模式安全
大都市中林立着許多高樓大廈,這些高樓大廈都是具備建築結構的大型建築。
在建築大樓時,須要先打牢地基,搭建架構,而後自下而上地一層一層蓋起來。
對於相似的,咱們首先建造這個物體的各個部分,而後分階段將它們組裝起來。
各個部分中的某些細節不一樣,構建出的產品表象會略有不一樣。
咱們能夠把物體看作一個產品,經過一個指揮者按照產品的建立步驟來一步步執行產品的建立。
當須要建立不一樣的產品時,只須要派生一個具體的建造者,重寫相應的組件構建方法便可。
class AnimalBuilder(object): def __init__(self, name, category=""): self.name = name self.category = category def buildHead(self): raise NotImplementedError def buildBody(self): raise NotImplementedError def buildLimb(self): raise NotImplementedError def getInfo(self): raise NotImplementedError class Bird(AnimalBuilder): def __init__(self, name): super(Bird, self).__init__(name) def buildHead(self): print("創造了鳥的頭部") def buildBody(self): print("創造了鳥的身體") def buildLimb(self): print("創造了鳥的四肢") def getInfo(self): print("這隻鳥是一隻%s" % self.name) class Fox(AnimalBuilder): def __init__(self, name): super(Fox, self).__init__(name) def buildHead(self): print("創造了狐狸的頭部") def buildBody(self): print("創造了狐狸的身體") def buildLimb(self): print("創造了狐狸的四肢") def getInfo(self): print("這隻狐狸是一隻%s" % self.name) class AnimalDirector(object): def __init__(self, animal): self.__animal = animal def createAniaml(self): self.__animal.buildHead() self.__animal.buildBody() self.__animal.buildLimb() def setAnimal(self, animal): self.__animal = animal def main(): bird = Bird("貓頭鷹") director = AnimalDirector(bird) director.createAniaml() bird.getInfo() fox = Fox("北極狐") director.setAnimal(fox) director.createAniaml() fox.getInfo() if "__main__" == __name__: main()
1 創造了鳥的頭部 2 創造了鳥的身體 3 創造了鳥的四肢 4 這隻鳥是一隻貓頭鷹 5 創造了狐狸的頭部 6 創造了狐狸的身體 7 創造了狐狸的四肢 8 這隻狐狸是一隻北極狐
4.單例模式
程序在運行時,一般都會生成不少實例
當咱們在想在程序中只表示某個東西時只會存在一個時,就會有「只能建立一個實例」的需求
當存在多個實例時,實例之間相互影響,可能會產生意想不到的Bug,可是,若是咱們能夠確保只有一個實例,就能夠放心的編程了
class Singleton(object): def __init__(self, name): self.name = name def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(Singleton, cls).__new__(cls) return cls._instance def main(): person = Singleton("alex") person2 = Singleton("bob") print(person.name) print(person2.name) if "__main__" == __name__: main()
1 bob 2 bob
# 解析代碼: 1.p = Person(name, age) 2.首先執行使用name和age參數來執行Person類的__new__方法,這個__new__方法會 返回Person類的一個實例(一般狀況下是使用 super(Persion, cls).__new__(cls, ... ...) 這樣的方式), 3.而後利用這個實例來調用類的__init__方法,上一步裏面__new__產生的實例也就是 __init__裏面的的 self 因此,__init__ 和 __new__ 最主要的區別在於: 1.__init__ 一般用於初始化一個新實例,控制這個初始化的過程,好比添加一些屬性, 作一些額外的操做,發生在類實例被建立完之後。它是實例級別的方法。 2.__new__ 一般用於控制生成一個新實例的過程。它是類級別的方法
5.適配器模式
應用場景:當咱們的電腦帶到香港時,不能直接插插頭使用,咱們電腦標準電壓和香港通用電壓不同,不能直接使用牆上的插口,須要中間加一個適配器,將電壓轉換爲咱們電腦適用的電壓。
一樣是電腦,作相同的工做,卻由於環境不一樣不能使用。Adapter 模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做。
將一個類的接口轉換成客戶但願的另一個接口。
class Person(object): def speak(self): raise NotImplementedError def write(self): raise NotImplementedError class Native(Person): def __init__(self, name): self.name = name def speak(self): print("%s 在用中文說話" % self.name) def write(self): print("%s 在寫中文" % self.name) class Foreigners(object): def __init__(self, name): self.name = name def foreignerSpeak(self): print("%s 在說蹩腳的中文" % self.name) def foreignerWrite(self): print("%s 在寫中文" % self.name) class Translator(Person): def __init__(self, foreigner=None): self.foreigner = foreigner def speak(self): self.foreigner.foreignerSpeak() def write(self): self.foreigner.foreignerWrite() def main(): p1 = Native("wang wu") p2 = Foreigners("alex") trans = Translator(p2) p1.speak() trans.speak() p1.write() trans.write() if "__main__" == __name__: main()
1 wang wu 在用中文說話 2 alex 在說蹩腳的中文 3 wang wu 在寫中文 4 alex 在寫中文
6.橋接模式
Bridge的意思是橋樑。就像在現實世界中,橋樑的功能是將河流的兩側鏈接起來同樣,Bridge模式的做用也是將兩樣東西鏈接起來,它們分別是類的功能層次結構和類的實現層次結構。 將抽象部分與實現部分分離,使它們均可以獨立的變化。 使用組合的功能,鏈接多維度的事物。 適用性: 1.若是一個系統須要在構件的抽象化角色和具體化角色之間增長更多的靈活性,避免在兩個層次之間創建靜態的聯繫。 2.設計要求實現化角色的任何改變不該當影響客戶端,或者說實現化角色的改變對客戶端是徹底透明的。 3.一個構件有多於一個的抽象化角色和實現化角色,系統須要它們之間進行動態耦合。 4.雖然在系統中使用繼承是沒有問題的,可是因爲抽象化角色和具體化角色須要獨立變化,設計要求須要獨立管理這二者。
class AbstractCollege(object): def __init__(self, name, major=None): self.name = name self.major = major def start(self): raise NotImplementedError class ComputerCollege(AbstractCollege): def __init__(self, name="計算機學院", major=None): super(ComputerCollege, self).__init__(name, major) def start(self): print("\n%s的" % self.name) self.major.start() class ArtCollege(AbstractCollege): def __init__(self, name="藝術學院", major=None): super(ArtCollege, self).__init__(name, major) def start(self): print("\n%s的" % self.name) self.major.start() class AbstractMajor(object): def __init__(self, name, course=None): self.name = name self.course = course def start(self): raise NotImplementedError class NetworkMajor(AbstractMajor): def __init__(self, name="網絡專業", course=None): super(NetworkMajor, self).__init__(name, course) def start(self): print("%s的" % self.name) self.course.start() class PerformMajor(AbstractMajor): def __init__(self, name="表演專業", course=None): super(PerformMajor, self).__init__(name, course) def start(self): print("%s的" % self.name) self.course.start() class AbstractCourse(object): def __init__(self, name): self.name = name def start(self): raise NotImplementedError class PythonCourse(AbstractCourse): def __init__(self, name="Python編程"): super(PythonCourse, self).__init__(name) def start(self): print("%s 課程開始了" % self.name) class TheoryOfPerformanceCourse(AbstractCourse): def __init__(self, name="表演理論"): super(TheoryOfPerformanceCourse, self).__init__(name) def start(self): print("%s 課程開始了" % self.name) def main(): # 三個維度的事物以組合的方式結合在一塊兒,互不影響,互相調用 coll1 = ComputerCollege() coll2 = ArtCollege() maj1 = NetworkMajor() maj2 = PerformMajor() cour1 = TheoryOfPerformanceCourse() cour2 = PythonCourse() coll1.major = maj1 coll2.major = maj2 maj1.course = cour1 maj2.course = cour2 coll1.start() coll2.start() if "__main__" == __name__: main()
1 計算機學院的 2 網絡專業的 3 表演理論 課程開始了 4 5 藝術學院的 6 表演專業的 7 Python編程 課程開始了
7.組合模式
在計算機的文件系統中,有「文件夾」的概念。文件夾裏面既能夠放入文件,也能夠放入其它文件夾。
將文件夾與文件都做爲目錄條目看待同樣,將容器和內容做爲同一種東西看待,容器中既能夠放內容,也能夠放小容器。
在子文件夾中,同樣地既能夠放入文件,也能夠放入子文件夾。能夠說,文件夾是造成一種容器結構、遞歸結構。
可以使容器與內容具備一致性,創造出遞歸結構的模式就是組合模式。
__author__ = 'Cq' class Entry(object): def getName(self): raise NotImplementedError def getSize(self): raise NotImplementedError def printList(self, prefix): raise NotImplementedError def add(self, entry): pass class File(Entry): def __init__(self, name, size): self.name = name self.size = size def getName(self): return self.name def getSize(self): return self.size def printList(self, prefix): print("file:[%s/%s] --> size:%s\n" % (prefix, self.name, self.getSize())) class Directory(Entry): def __init__(self, name): self.name = name self.directory = [] def getName(self): return self.name def getSize(self): size = 0 for i in self.directory: size += i.getSize() return size def printList(self, prefix=""): prefix += "/"+self.name print("[%s] --> size:%s " % (prefix, self.getSize())) for i in self.directory: i.printList(prefix) def add(self, entry): self.directory.append(entry) def main(): print("-----------Prepare the root file directory...") rootdir = Directory("root") bindir = Directory("bin") tmpdir = Directory("tmp") usrdir = Directory("usr") rootdir.add(bindir) rootdir.add(tmpdir) rootdir.add(usrdir) bindir.add(File("httpd", 2000)) usrdir.add(File("python", 5000)) rootdir.printList() print("\n-------------Prepare the usr file directory...") javadir = Directory("java") godir = Directory("go") phpdir = Directory("php") usrdir.add(javadir) usrdir.add(godir) usrdir.add(phpdir) javadir.add(File("hello.java", 20)) godir.add(File("hello.go", 100)) phpdir.add(File("hello.php", 50)) rootdir.printList() if "__main__" == __name__: main()
1 -----------Prepare the root file directory... 2 [/root] --> size:7000 3 [/root/bin] --> size:2000 4 file:[/root/bin/httpd] --> size:2000 5 6 [/root/tmp] --> size:0 7 [/root/usr] --> size:5000 8 file:[/root/usr/python] --> size:5000 9 10 11 -------------Prepare the usr file directory... 12 [/root] --> size:7170 13 [/root/bin] --> size:2000 14 file:[/root/bin/httpd] --> size:2000 15 16 [/root/tmp] --> size:0 17 [/root/usr] --> size:5170 18 file:[/root/usr/python] --> size:5000 19 20 [/root/usr/java] --> size:20 21 file:[/root/usr/java/hello.java] --> size:20 22 23 [/root/usr/go] --> size:100 24 file:[/root/usr/go/hello.go] --> size:100 25 26 [/root/usr/php] --> size:50 27 file:[/root/usr/php/hello.php] --> size:50
8.外觀模式
程序這東西老是會變的愈來愈大。隨着時間的推移,程序中的類會愈來愈多,並且,它們之間相互關聯,這會致使程序結構也變得愈來愈複雜。 特別是在調用大型程序進行處理時,咱們須要格外注意哪些數量龐大的類之間錯綜複雜的關係。 不過與其這麼作,不如爲這個大型程序準備一個「窗口」,只須要簡單地對「窗口」提出請求便可。 Facade模式,不只作到,還考慮到系統內部各個類之間的責任關係和依賴關係,按照正確的順序調用各個類。 在如下狀況下能夠考慮使用外觀模式: (1)設計初期階段,應該有意識的將不一樣層分離,層與層之間創建外觀模式。 (2) 開發階段,子系統愈來愈複雜,增長外觀模式提供一個簡單的調用接口。 (3) 維護一個大型遺留系統的時候,可能這個系統已經很是難以維護和擴展,但又包含很是重要的功能,爲其開發一個外觀類,以便新系統與其交互。 優勢: (1)實現了子系統與客戶端之間的鬆耦合關係。 (2)客戶端屏蔽了子系統組件,減小了客戶端所需處理的對象數目,並使得子系統使用起來更加容易。
__author__ = 'Cq' class Stock(): def __init__(self, name="股票"): self.name = name def buy(self): print('買 '+self.name) def sell(self): print('賣 '+self.name) class ETF(): def __init__(self, name="指數型基金"): self.name = name def buy(self): print('買 '+self.name) def sell(self): print('賣 '+self.name) class Future(): def __init__(self, name="期貨"): self.name = name def buy(self): print('買 '+self.name) def sell(self): print('賣 '+self.name) class NationDebt(): def __init__(self, name="國債"): self.name = name def buy(self): print('買 '+self.name) def sell(self): print('賣 '+self.name) class Option(): def __init__(self, name="權證"): self.name = name def buy(self): print('買 '+self.name) def sell(self): print('賣 '+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 main(): myfund = Fund() myfund.buyFund() myfund.sellFund() if __name__ == '__main__': main()
1 買 股票 2 買 指數型基金 3 買 國債 4 買 期貨 5 買 權證 6 賣 股票 7 賣 指數型基金 8 賣 期貨 9 賣 國債 10 賣 權證
9.原型模式
在開發的過程當中,有時候會有「在不指定類名的前提下生成實例」的需求。 在如下狀況下能夠考慮使用原型模式: (1)對象種類繁多,沒法將它們整合到一個類中的 對象太多,若是將它們分別做爲一個類,必須編寫不少類文件 (2)難以根據類生成實例時 生成實例的過程太過複雜,很難根據類來生成實例。 咱們會預先將想生成的實例保存起來,而後在須要時經過複製來生成新的實例 (3)想解耦框架與生成的實例時 想讓生成實例的框架不依賴與具體的類。這時,不能指定類名來生成實例,而事先「註冊」一個「原型」實例,而後經過負責該實例來生成新的實例
__author__ = 'Cq' from copy import copy, deepcopy class Model(object): def __init__(self, mid): self.id = mid def display(self): raise NotImplementedError def clone(self): raise NotImplementedError def deepClone(self): raise NotImplementedError class Materials(object): def __init__(self, name): self.name = name class Teapot(Model): def __init__(self, name, mid, materials="塑料"): self.name = name self.materials = Materials(materials) super(Teapot, self).__init__(mid) def display(self): print(">> name:%s id:%s materials:%s" % (self.name, self.id, self.materials.name)) def clone(self): return copy(self) def deepClone(self): return deepcopy(self) class Manager(object): def __init__(self): self.dicts = {} def register(self, name, model): self.dicts[name] = model def create(self, model_name): return self.dicts[model_name].clone() def deepCreate(self, model_name): return self.dicts[model_name].deepClone() def main(): manager = Manager() blue = Teapot("blue model", "001") red = Teapot("red model", "002") white = Teapot("white model", "003") manager.register(blue.name, blue) manager.register(red.name, red) manager.register(white.name, white) blue_teapot = manager.create("blue model") blue_teapot.name = "blue rosewood teapot" blue2_teapot = manager.deepCreate("blue model") blue2_teapot.name = "blue stainless steel teapot" blue_teapot.materials.name = "花梨木" blue2_teapot.materials.name = "不鏽鋼" blue.display() blue_teapot.display() blue2_teapot.display() if '__main__' == __name__: main()
1 >> name:blue model id:001 materials:花梨木 2 >> name:blue rosewood teapot id:001 materials:花梨木 3 >> name:blue stainless steel teapot id:001 materials:不鏽鋼
# 結果解析: 因爲blue_teapot(藍色花梨木茶壺)實例沒有深度複製實例(藍色茶壺模型),致使materials對象沒有被複制,當blue_teapot修改變量時,影響到了原來的實例 而blue2_teapot(藍色不鏽鋼茶壺)實例對blue進行了深度複製,與原實例是如出一轍的copy對象,它們之間沒有關聯
10.享元模式
Flyweight是「輕量級」的意思,然而對象在計算機中是虛擬存在的東西,它的「重」和「輕」並不是指實際重量,然而是它們「使用的內存大小」。
使用內存多的對象就是「重」對象,使用內存少的對象就是「輕」對象。
Flyweight模式就是,經過儘可能共享實例來避免建立出新的實例。
抽象享元角色(Flyweight):此角色是全部的具體享元類的超類,爲這些類規定出須要實現的公共接口或抽象類。那些須要外部狀態(External State)的操做能夠經過方法的參數傳入。抽象享元的接口使得享元變得可能,可是並不強制子類實行共享,所以並不是全部的享元對象都是能夠共享的。
具體享元(ConcreteFlyweight)角色:實現抽象享元角色所規定的接口。若是有內部狀態的話,必須負責爲內部狀態提供存儲空間。享元對象的內部狀態必須與對象所處的周圍環境無關,從而使得享元對象能夠在系統內共享。有時候具體享元角色又叫作單純具體享元角色,由於複合享元角色是由單純具體享元角色經過複合而成的。
複合享元(UnsharableFlyweight)角色:複合享元角色所表明的對象是不能夠共享的,可是一個複合享元對象能夠分解成爲多個自己是單純享元對象的組合。複合享元角色又稱作不可共享的享元對象。這個角色通常不多使用。
享元工廠(FlyweightFactoiy)角色:本角色負責建立和管理享元角色。本角色必須保證享元對象能夠被系統適當地共享。當一個客戶端對象請求一個享元對象的時候,享元工廠角色須要檢查系統中是否已經有一個符合要求的享元對象,若是已經有了,享元工廠角色就應當提供這個已有的享元對象;若是系統中沒有一個適當的享元對象的話,享元工廠角色就應當建立一個新的合適的享元對象。
客戶端(Client)角色:本角色還須要自行存儲全部享元對象的外部狀態。
內部狀態與外部狀態:在享元對象內部而且不會隨着環境改變而改變的共享部分,能夠稱之爲享元對象的內部狀態,反之隨着環境改變而改變的,不可共享的狀態稱之爲外部狀態。
__author__ = 'Cq' 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) ) # setdefault返回父類的new方法,當實例化的類是同一類,而且傳遞的參數同樣時,則返回之前半實例化的new方法對象(內存中已經存在) # 將觸發BoardShoes子類或Sneaker子類的構造方法 def display(self): raise NotImplementedError class BoardShoes(FlyweightBase): def __init__(self, size, brand): self.size = size self.brand = brand def display(self): print("This pair of %s-yard board shoes is %s" % (self.size, self.brand)) class Sneaker(FlyweightBase): def __init__(self, size, brand): self.size = size self.brand = brand def display(self): print("This pair of %s-yard sneakers is %s" % (self.size, self.brand)) def main(): shoes1 = BoardShoes(40, "Nike") shoes2 = BoardShoes(40, "Nike") shoes3 = Sneaker(40, "Adidas") shoes1.display() print(">>id:", id(shoes1), "\n") shoes2.display() print(">>id:", id(shoes2), "\n") shoes3.display() print(">>id:", id(shoes3), "\n") if "__main__" == __name__: main()
1 This pair of 40-yard board shoes is Nike 2 >>id: 35780312 3 4 This pair of 40-yard board shoes is Nike 5 >>id: 35780312 6 7 This pair of 40-yard sneakers is Adidas 8 >>id: 35780368
11.代理模式
Proxys "代理人"的意思,它指的是代替別人進行工做的人。 在直接訪問對象時帶來的問題,好比說:要訪問的對象在遠程的機器上。在面向對象系統中,有些對象因爲某些緣由(好比對象建立開銷很大,或者某些操做須要安全控制,或者須要進程外的訪問),直接訪問會給使用者或者系統結構帶來不少麻煩,咱們能夠在訪問此對象時加上一個對此對象的訪問層。 當不必定須要本人親自進行工做時,就能夠尋找代理人去完成工做。 當代理人遇到沒法本身解決的事情時就會去找本人解決該問題。 實現:增長中間層,實現與被代理類組合。
__author__ = 'Cq' class Printable(object): def setPrinterName(self, name): raise NotImplementedError def getPrinterName(self): raise NotImplementedError def print(self, string): raise NotImplementedError class Printer(Printable): def __init__(self, name): self.name = name def setPrinterName(self, name): self.name = name def getPrinterName(self): return self.name def print(self, string): print("----------%s----------" % self.name) print(string) class PrinterProxy(Printable): def __init__(self, name, printer=None): self.name = name self.real = printer def setPrinterName(self, name): if self.real is not None: self.real.setPrinterName(name) self.name = name def getPrinterName(self): return self.name def print(self, string): self.realize() self.real.print(string) def realize(self): if self.real is None: print("設置被代理人%s..." % self.name) self.real = Printer(self.name) def main(): p1 = Printer("Alice") p2 = PrinterProxy("Bob") # 使用打印機打印資料 p1.print("打印資料中...\n") # 使用打印機代理打印資料,未指定被代理人,自動建立被代理人 p2.print("打印代理打印資料中...\n") # 修改被代理人 p2.setPrinterName("Seven") p2.print("打印代理繼續打印資料中...\n") # 刪除被代理人,自動建立被代理人 p2.real = None p2.setPrinterName("Alex") p2.print("打印代理繼續繼續打印資料中...") if "__main__" == __name__: main()
1 ----------Alice---------- 2 打印資料中... 3 4 設置被代理人Bob... 5 ----------Bob---------- 6 打印代理打印資料中... 7 8 ----------Seven---------- 9 打印代理繼續打印資料中... 10 11 設置被代理人Alex... 12 ----------Alex---------- 13 打印代理繼續繼續打印資料中...
12.裝飾器模式
假如如今有一塊蛋糕,若是隻塗上奶油,其它什麼都不加,就是奶油蛋糕。若是加上草莓,就是草莓奶油蛋糕。若是加上一塊黑色巧克力板,上面用白色巧克力寫上姓名,而後插上表明年齡的蠟燭,就變成了一塊生日蛋糕。
不管是蛋糕、奶油蛋糕、草莓蛋糕仍是生日蛋糕,它們的核心都是蛋糕。
像這樣不斷地對對象添加裝飾的設計模式稱爲裝飾器模式
__author__ = 'Cq' ''' 該案例爲字符串加上邊框線條裝飾,實現裝飾器模式 ''' class Display(object): ''' 用於顯示字符串的抽象類 ''' def getColumns(self): ''' 獲取橫向字符數 :return: ''' raise NotImplementedError def getRows(self): ''' 獲取縱向行數 :return: ''' raise NotImplementedError def getRowText(self, row): ''' 獲取第row行的字符串 :return: ''' raise NotImplementedError def show(self): for i in range(self.getRows()): print(self.getRowText(i)) class StringDisplay(Display): ''' 用於顯示單行字符串的類 ''' def __init__(self, string): self.__string = string def getColumns(self): return len(self.__string) def getRows(self): return 1 def getRowText(self, row): if row == 0: return self.__string else: return None class Border(Display): ''' 用於顯示裝飾邊框的抽象類 ''' def __init__(self, display): self.display = display class SideBorder(Border): ''' 用於顯示左右邊框的類 ''' def __init__(self, display, ch): super(SideBorder, self).__init__(display) self.borderChar = ch def getColumns(self): return 1 + self.display.getColumns() + 1 def getRows(self): return self.display.getRows() def getRowText(self, row): return self.borderChar + self.display.getRowText(row) + self.borderChar class FullBorder(Border): ''' 用於顯示上下左右邊框的類 ''' def __init__(self, display): super(FullBorder, self).__init__(display) def getColumns(self): return 1 + self.display.getColumns() + 1 def getRows(self): return 1 + self.display.getRows() + 1 def getRowText(self, row): if row == 0: return "+" + self.makeLine('-', self.display.getColumns()) + "+" elif row == self.display.getRows() + 1: return "+" + self.makeLine('-', self.display.getColumns()) + "+" else: return "|" + self.display.getRowText(row - 1) + "|" def makeLine(self, ch, count): string = "" for i in range(count): string += ch return string def main(): b1 = StringDisplay("Hello world!") b2 = SideBorder(b1, '#') b3 = FullBorder(b2) b1.show() print('=====================================') b2.show() print('=====================================') b3.show() print('=====================================') b4 = SideBorder(FullBorder(FullBorder(SideBorder(FullBorder(StringDisplay("你好,世界!")), '*'))), '/') b4.show() print('=====================================') if '__main__' == __name__: main()
1 Hello world! 2 ===================================== 3 #Hello world!# 4 ===================================== 5 +--------------+ 6 |#Hello world!#| 7 +--------------+ 8 ===================================== 9 /+------------+/ 10 /|+----------+|/ 11 /||*+------+*||/ 12 /||*|你好,世界!|*||/ 13 /||*+------+*||/ 14 /|+----------+|/ 15 /+------------+/ 16 =====================================
13.模板方法模式
組成模板的方法被定義在父類中。因爲這些方法是抽象方法,因此只查看父類的代碼是沒法知道這些方法最終會進行何種具體處理的,惟一能知道的就是父類是如何調用這些方法的。
實現抽象方法的是子類,在子類中實現了抽象方法也就決定了具體的處理。
只要在不一樣的子類中實現不一樣的具體處理,當父類的模板方法被調用時程序行爲也會不一樣。
在父類中定義處理流程的框架,在子類中實現具體處理的模式就稱爲模板方法模式。
__author__ = 'Cq' class AbstractDevice(object): def powerOn(self): raise NotImplementedError def knobDown(self): raise NotImplementedError def startingUp(self): raise NotImplementedError class Servers(AbstractDevice): def powerOn(self): print("插上服務器電源線") def knobDown(self): print("按下服務器開機按鈕") def startingUp(self): self.powerOn() self.knobDown() class Computer(AbstractDevice): def powerOn(self): print("插上電腦電源線") def knobDown(self): print("按下電腦開機按鈕") def startingUp(self): self.powerOn() self.knobDown() def main(): s = Servers() c = Computer() s.startingUp() c.startingUp() if "__main__" == __name__: main()
1 插上服務器電源線 2 按下服務器開機按鈕 3 插上電腦電源線 4 按下電腦開機按鈕
14.責任鏈模式
使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。
例如:
當外部請求程序進行某個處理,但程序暫時沒法直接決定由哪一個對象負責處理時,就須要推卸責任。
這種狀況下,咱們能夠考慮將多個對象組成一條職責鏈,而後按照它們在職責鏈上的順序一個一個地找出到底應該誰來負責處理。
這種模式稱爲「職責鏈」。
__author__ = 'Cq' class BaseHandler(object): ''' 處理基類 ''' def successor(self, successor): # 與下一個責任者關聯 self._successor = successor class RequestHandlerL1(BaseHandler): ''' 第一級請求處理者 ''' name = "導員" def handle(self, request): if request < 2: print("審批者[%s],請假天數[%s],審批結果[審批經過]" % (self.name, request)) else: print("\033[31;1m[%s]無權審批,交給下一個審批者\033[0m" %self.name) self._successor.handle(request) class RequestHandlerL2(BaseHandler): '''第二級請求處理者''' name = "班主任" def handle(self, request): if request < 7: print("審批者[%s],請假天數[%s],審批結果[審批經過]" % (self.name, request)) else: print("\033[31;1m[%s]無權審批,交給下一個審批者\033[0m" % self.name) self._successor.handle(request) class RequestHandlerL3(BaseHandler): '''第三級請求處理者''' name = "教學院長" def handle(self, request): if request < 15: print("審批者[%s],請假天數[%s],審批結果[審批經過]" % (self.name, request)) else: print("\033[31;1m[%s]無權審批,交給下一個審批者\033[0m" % self.name) self._successor.handle(request) class RequestHandlerL4(BaseHandler): '''第四級請求處理者''' name = "校長" def handle(self, request): if request < 90: 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() h4 = RequestHandlerL4() h1.successor(h2) h2.successor(h3) h3.successor(h4) def __init__(self, name, days): self.name = name self.days = days def handle(self): # 出責任鏈最低級開始 self.h1.handle(self.days) def setDays(self, days): self.days = days def main(): r1 = RequestAPI("老王", 1) r1.handle() print(r1.__dict__, "\n") r1.setDays(5) r1.handle() print(r1.__dict__, "\n") r1.setDays(10) r1.handle() print(r1.__dict__, "\n") r1.setDays(30) r1.handle() print(r1.__dict__, "\n") r1.setDays(100) r1.handle() print(r1.__dict__, "\n") if "__main__" == __name__: main()
1 審批者[導員],請假天數[1],審批結果[審批經過] 2 {'name': '老王', 'days': 1} 3 4 [導員]無權審批,交給下一個審批者 5 審批者[班主任],請假天數[5],審批結果[審批經過] 6 {'name': '老王', 'days': 5} 7 8 [導員]無權審批,交給下一個審批者 9 [班主任]無權審批,交給下一個審批者 10 審批者[教學院長],請假天數[10],審批結果[審批經過] 11 {'name': '老王', 'days': 10} 12 13 [導員]無權審批,交給下一個審批者 14 [班主任]無權審批,交給下一個審批者 15 [教學院長]無權審批,交給下一個審批者 16 審批者[校長],請假天數[30],審批結果[審批經過] 17 {'name': '老王', 'days': 30} 18 19 [導員]無權審批,交給下一個審批者 20 [班主任]無權審批,交給下一個審批者 21 [教學院長]無權審批,交給下一個審批者 22 [校長]請假天數太多了,不批 23 {'name': '老王', 'days': 100}
15.觀察者模式
定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時, 全部依賴於它的對象都獲得通知並被自動更新。
Oberver的意思是「進行觀察的人」,也就是「觀察者」的意思。
當觀察對象的狀態發生變化時,會通知給觀察者。
__author__ = 'Cq' 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.name)) 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 __init__(self, name="共軍觀察者"): self.name = name def update(self, observer_subject): print("共軍:收到[%s]消息[%s] "%(observer_subject.name,observer_subject.msg)) class GMDViewer(object): def __init__(self, name="國軍觀察者"): self.name = name def update(self, observer_subject): print("國軍:收到[%s]消息[%s] " % (observer_subject.name,observer_subject.msg)) def 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 __name__ == "__main__": main()
1 [共軍放哨者]已經將[共軍觀察者]加入觀察隊列... 2 [共軍放哨者]已經將[國軍觀察者]加入觀察隊列... 3 [國軍放哨者]已經將[國軍觀察者]加入觀察隊列... 4 共軍:收到[共軍放哨者]消息[敵人來了...] 5 國軍:收到[共軍放哨者]消息[敵人來了...] 6 國軍:收到[國軍放哨者]消息[前方發現敵人,請緊急撤離,不要告訴共軍]
16.策略模式
一個系統有許多許多類,而區分它們的只是他們直接的行爲。 不管什麼程序,其目的都是解決問題。而爲了解決問題,咱們又須要編寫特定的算法。 使用Strategy模式能夠總體地替換算法的實現部分。 即旅行的出遊方式:選擇騎自行車、坐汽車,每一種旅行方式都是一個策略。 實現: 1.對策略對象定義一個公共接口。 2.編寫策略類,該類實現了上面的公共接口。 3.在使用策略對象的類中保存一個對策略對象的引用。 4.在使用策略對象的類中,實現對策略對象的set和get方法或者使用構造方法完成賦值。
__author__ = 'Cq' class TravelStrategy(object): def set_sail(self): raise NotImplementedError class AirplaneStrategy(TravelStrategy): def set_sail(self): print("\033[32;1m坐飛機去旅行...\033[0m") class TrainStrategy(TravelStrategy): def set_sail(self): print("\033[32;1m坐火車去旅行...\033[0m") class CarStrategy(TravelStrategy): def set_sail(self): print("\033[32;1m開轎車去旅行...\033[0m") class BicycleStrategy(TravelStrategy): def set_sail(self): print("\033[32;1m騎自行車去旅行...\033[0m") class FootStrategy(TravelStrategy): def set_sail(self): print("\033[32;1m徒步去旅行...\033[0m") class ShipStrategy(TravelStrategy): def set_sail(self): print("\033[32;1m作船去旅行...\033[0m") class TravelManager(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.set_sail() def main(): travel = TravelManager(AirplaneStrategy()) travel.travel() travel.set_strategy(TrainStrategy()) travel.travel() travel.set_strategy(ShipStrategy()) travel.travel() travel.set_strategy(CarStrategy()) travel.travel() travel.set_strategy(BicycleStrategy()) travel.travel() travel.set_strategy(FootStrategy()) travel.travel() if "__main__" == __name__: main()
1 坐飛機去旅行... 2 坐火車去旅行... 3 作船去旅行... 4 開轎車去旅行... 5 騎自行車去旅行... 6 徒步去旅行...
17.命令模式
一個類在進行工做時會調用本身或是其餘類的方法,雖然調用結果會反映在對象的狀態中,但並不會留下工做的歷史記錄
這時,若是咱們有一個類,用來表示「請進行這項工做」的「命令」就會方便不少。
每一項想作的工做就再也不是「方法的調用」這種動態處理了,而是一個表示命令的類的實例,既能夠用「物」來表示。
只須要管理這些實例的集合便可,並且還能夠隨時再次執行過去的命令,或是將多個過去的命令整合爲一個新命令並執行
Command模式可應用於
a)整個調用過程比較繁雜,或者存在多處這種調用。這時,使用Command類對該調用加以封裝,便於功能的再利用。
b)調用先後須要對調用參數進行某些處理。
c)調用先後須要進行某些額外處理,好比日誌,緩存,記錄歷史操做等。
Command模式有以下效果:
a)將調用操做的對象和知道如何實現該操做的對象解耦。
b)Command是頭等對象。他們能夠像其餘對象同樣被操做和擴展。
c)你可將多個命令裝配成一個符合命令。
d)增長新的Command很容易,由於這無需改變現有的類。
__author__ = 'Cq' class Command(object): def execute(self): raise NotImplementedError class MacroCommand(Command): def __init__(self): self.commands = [] def execute(self): for i in self.commands: i.execute() def appends(self, cmd): self.commands.append(cmd) print("命令添加成功") def undo(self): if len(self.commands): self.commands.pop() print("命令刪除成功") def clear(self): while len(self.commands): self.commands.pop() print("全部命令清除成功") class RunCommand(Command): def execute(self): print("執行[跑]命令中...") class JumpCommand(Command): def execute(self): print("執行[跳]命令中...") class RollCommand(Command): def execute(self): print("執行[滾]命令中...") def main(): execs = MacroCommand() execs.appends(RunCommand()) execs.execute() print("\n") execs.appends(JumpCommand()) execs.appends(RollCommand()) execs.execute() print("\n") execs.undo() execs.execute() print("\n") execs.clear() execs.execute() if "__main__" == __name__: main()
1 命令添加成功 2 執行[跑]命令中... 3 4 5 命令添加成功 6 命令添加成功 7 執行[跑]命令中... 8 執行[跳]命令中... 9 執行[滾]命令中... 10 11 12 命令刪除成功 13 執行[跑]命令中... 14 執行[跳]命令中... 15 16 17 全部命令清除成功
18.訪問者模式
在數據結構中保存着許多元素,咱們會對這些元素進行「處理」。這時,「處理」代碼放在哪裏比較好呢?一般的作法是將它們放在表示數據結構的類中。
可是,若是「處理」有許多種?這種狀況下,每當增長一種處理,咱們就不得不去修改表示數據結構的類。
在Visitor模式中,數據結構與處理被分離開來。咱們編寫一個表示「訪問者」的類來訪問數據結構中的元素,並把對各元素的處理交給訪問者類。
這樣,當須要增長新的處理時,咱們只須要編寫新的訪問者,而後讓數據結構能夠接受訪問者的訪問便可。
__author__ = 'Cq' class Visitor(object): def visit(self, file_or_dir): raise NotImplementedError class Element(object): def accept(self, visitor): raise NotImplementedError class Entry(Element): def getName(self): raise NotImplementedError def getSize(self): raise NotImplementedError def add(self, entry): pass def __str__(self): return self.getName() + " (" + str(self.getSize()) + ")" class File(Entry): def __init__(self, name, size): self.name = name self.size = size def getName(self): return self.name def getSize(self): return self.size def accept(self, visitor): visitor.visit(self) class Directory(Entry): def __init__(self, name): self.name = name self.dirs = [] self.index = -1 def getName(self): return self.name def getSize(self): size = 0 for i in self.dirs: size += i.getSize() return size def add(self, entry): self.dirs.append(entry) return self def __iter__(self): return self def __next__(self): if len(self.dirs) - 1 == self.index: self.index = -1 raise StopIteration else: self.index += 1 return self.dirs[self.index] def accept(self, visitor): visitor.visit(self) class ListVisitor(Visitor): currentdir = "" def visit(self, file_or_dir): if isinstance(file_or_dir, File): print(self.currentdir + "/", file_or_dir, sep="") else: print(self.currentdir + "/", file_or_dir, sep="") savedir = self.currentdir self.currentdir += "/" + file_or_dir.getName() for ever_dir in file_or_dir: ever_dir.accept(self) self.currentdir = savedir def main(): print("Making root entries...") root_dir = Directory("root") bin_dir = Directory("bin") tmp_dir = Directory("tmp") usr_dir = Directory("usr") root_dir.add(bin_dir) root_dir.add(tmp_dir) root_dir.add(usr_dir) bin_dir.add(File("file1", 10000)) bin_dir.add(File("file2", 10000)) root_dir.accept(ListVisitor()) print("\n") print("Making root entries...") taobao_dir = Directory("taobao") jingdong_dir = Directory("jingdong") tianmao_dir = Directory("tianmao") usr_dir.add(taobao_dir) usr_dir.add(jingdong_dir) usr_dir.add(tianmao_dir) taobao_dir.add(File("file3.java", 100)) taobao_dir.add(File("file4.php", 200)) jingdong_dir.add(File("file5.go", 400)) jingdong_dir.add(File("file6.sh", 600)) tianmao_dir.add(File("file7.c", 700)) root_dir.accept(ListVisitor()) if "__main__" == __name__: main()
1 Making root entries... 2 /root (20000) 3 /root/bin (20000) 4 /root/bin/file1 (10000) 5 /root/bin/file2 (10000) 6 /root/tmp (0) 7 /root/usr (0) 8 9 10 Making root entries... 11 /root (22000) 12 /root/bin (20000) 13 /root/bin/file1 (10000) 14 /root/bin/file2 (10000) 15 /root/tmp (0) 16 /root/usr (2000) 17 /root/usr/taobao (300) 18 /root/usr/taobao/file3.java (100) 19 /root/usr/taobao/file4.php (200) 20 /root/usr/jingdong (1000) 21 /root/usr/jingdong/file5.go (400) 22 /root/usr/jingdong/file6.sh (600) 23 /root/usr/tianmao (700) 24 /root/usr/tianmao/file7.c (700)
19.仲裁者模式
Mediator的意思是「衝裁者」、「中介者」。一方面,當發生麻煩事情的時候,通知仲裁者;當發生涉及全體組員的事情時,也通知仲裁者。當仲裁者下達指示時,組員當即執行。
團隊組員之間再也不互相共同並私自作出決定,而是發生任何事情都向仲裁者報告。另外一方面,仲裁者站在整個團隊的角度上對組員上報的事情作出決定。這就是Mediator模式。
重要角色:
Mediator 仲裁者
Colleague 組員
__author__ = 'Cq' ''' 本例子使用博物館經過門禁案例,描述仲裁者模式 工做人員想要進入博物館首先要在大門口刷門禁卡才能進入, 其次想要進入樓宇內要在一樓門禁刷門禁卡,可是,必須再刷過大門口的門禁後,該門禁才能刷卡經過。 然後進入各個樓層的藏物展覽廳內,要在展覽廳門口刷門禁,可是,前提是大門口門禁刷過而且樓宇門禁也刷過,該門禁才能刷卡經過 可見個個門禁間有依賴關係,前一個門禁影響後一個門禁,若是咱們在門禁間單首創建關聯函數,至少要維護n-1個關係 如今門禁數量只有3個,若是之後要擴展呢?n-1個關聯函數都必需要重寫,是否是很麻煩? 這個時候引用仲裁者模式尤其重要! ''' class Mediator(object): ''' 仲裁者抽象類 ''' def addColleagues(self, colleague): raise NotImplementedError def colleagueChange(self, colleague): raise NotImplementedError class Colleague(object): ''' 組員抽象類 ''' def setMediator(self, mediator): raise NotImplementedError def setColleagueAllowable(self, boolean): raise NotImplementedError class ColleagueGate(Colleague): ''' 組員:大門 ''' def __init__(self, mediator=None): self.mediator = mediator self.allowable = False def setMediator(self, mediator): self.mediator = mediator def setColleagueAllowable(self, boolean): self.allowable = boolean self.mediator.colleagueChange(self) return self.mediator.permit(self) class ColleagueEntrance(Colleague): ''' 組員:樓宇門 ''' def __init__(self, mediator=None): self.mediator = mediator self.allowable = False def setMediator(self, mediator): self.mediator = mediator def setColleagueAllowable(self, boolean): self.allowable = boolean self.mediator.colleagueChange(self) return self.mediator.permit(self) class ColleagueDoor(Colleague): ''' 組員:展覽廳門 ''' def __init__(self, mediator=None): self.mediator = mediator self.allowable = False def setMediator(self, mediator): self.mediator = mediator def setColleagueAllowable(self, boolean): self.allowable = boolean self.mediator.colleagueChange(self) return self.mediator.permit(self) class MediatorEntrance(Mediator): ''' 仲裁者類 ''' def __init__(self): self.allows = {} def addColleagues(self, colleague): colleague.setMediator(self) self.allows[colleague.__class__] = [len(self.allows) + 1] self.allows[colleague.__class__].append(False) def colleagueChange(self, colleague): ''' 接收組員的變化信息,並處理 :param colleague: :return: ''' ''' :param colleague: :return: ''' self.allows[colleague.__class__][1] = colleague.allowable def permit(self, colleague): ''' 反饋給組員信息 :param colleague: :return: True or False ''' per = True for k in self.allows.values(): if k[0] < self.allows[colleague.__class__][0]: if not k[1]: per = False return per def restore(self): for i in self.allows.values(): i[1] = False def main(): med = MediatorEntrance() gate = ColleagueGate() entrance = ColleagueEntrance() door = ColleagueDoor() med.addColleagues(gate) med.addColleagues(entrance) med.addColleagues(door) print("工做者進入大門") print("\033[32;1m>>", gate.setColleagueAllowable(True), "\033[0m") print("工做者進入樓宇門") print("\033[32;1m>>", entrance.setColleagueAllowable(True), "\033[0m") print("工做者進入展覽廳門") print("\033[32;1m>>", door.setColleagueAllowable(True), "\033[0m") # 還原門禁 med.restore() print("偷竊者翻過圍牆進入庭院") print("偷竊者使用偷來的門禁刷樓宇門") print("\033[31;1m>>", entrance.setColleagueAllowable(True), "\033[0m") # 還原門禁 med.restore() print("偷竊者翻過圍牆進入庭院") print("偷竊者爬入樓宇進入樓層走道") print("偷竊者使用偷來的門禁刷樓宇門") print("\033[31;1m>>", entrance.setColleagueAllowable(True), "\033[0m") if "__main__" == __name__: main()
1 工做者進入大門 2 >> True 3 工做者進入樓宇門 4 >> True 5 工做者進入展覽廳門 6 >> True 7 偷竊者翻過圍牆進入庭院 8 偷竊者使用偷來的門禁刷樓宇門 9 >> False 10 偷竊者翻過圍牆進入庭院 11 偷竊者爬入樓宇進入樓層走道 12 偷竊者使用偷來的門禁刷樓宇門 13 >> False
20.忘備錄模式
咱們在使用文本比編輯器編寫文本時,若是不當心刪除了某句話,能夠經過撤銷(undo)功能將文件恢復至以前的狀態。有些文本編輯器甚至支持屢次撤銷,可以恢復至好久以前的版本。
使用面向對象編程的方式實現撤銷功能時,須要事先保存實例的相關狀態信息。而後,在撤銷是,還須要根據所保存的信息將實例恢復至原來的狀態。
想要恢復實例,須要一個能夠自由訪問實例內部結構的權限。可是,若是稍有不注意,又可能會將依賴於實例內部結構的代碼分散地編寫在程序中的各個地方,致使程序變得難以維護。這種狀況就叫做「破壞了封裝性」。
經過引入表示實例狀態的角色,能夠在保存和恢復實例時有效地防止對象的封裝性遭到破壞。
__author__ = 'Cq' import random class Memento(object): ''' 遊戲角色存檔類 ''' def __init__(self, money, killed, hp, gnum): self.money = money self.killed = killed self.hp = hp self.gnum = gnum def changeKilled(self, count): self.killed = count def changeHP(self, count): self.hp = count def changeMoney(self, count): self.money = count def changeGameNum(self, count): self.gnum = count class Gamer(object): ''' 遊戲角色類 ''' def __init__(self, money, killed=0, hp=100, gnum=1): self.__money = money self.__killed = killed self.__hp = hp self.__gnum = gnum self.__memento = [] def getMoney(self): return self.__money def getKilled(self): return self.__killed def getHP(self): return self.__hp def getGameNum(self): return self.__gnum def through(self): self.__gnum += 1 money = random.randint(10, 100) killed = random.randint(20, 50) print("\033[32;1m經過關卡,金錢+%s\033[0m" % money) self.__money += money print("\033[32;1m經過關卡,消滅敵人%s\033[0m" % killed) self.__killed += killed def lossHP(self): _hp = random.randint(0, 20) print("損失生命值:%s" % _hp) self.__hp -= _hp self.isDie() def isDie(self): if self.__hp <= 0: self.gameOver() else: self.through() def gameOver(self): print("\033[31;1m人物死亡,通關失敗\033[0m") self.__hp = 0 def startGame(self): if self.__hp == 0: print("遊戲角色死亡,請從新開始遊戲或者讀取存檔") self.restoreMemento() return else: res = random.randint(0, 10) if res <= 2: self.gameOver() else: self.lossHP() def createMemento(self): self.__memento.append(Memento(self.__money, self.__killed, self.__hp, self.__gnum)) def restoreMemento(self): print("讀取存檔...") self.__money = self.__memento[-1].money self.__killed = self.__memento[-1].killed self.__hp = self.__memento[-1].hp self.__gnum = self.__memento[-1].gnum def __str__(self): return "[遊戲角色] 金錢數:%s 消滅敵人數:%s 已經過關卡:%s 當前血量:%s" % (self.__money, self.__killed, self.__gnum, self.__hp) def main(): print("建立遊戲角色") role = Gamer(0) print("存檔中...") m_list = [] m_list.append(role.createMemento()) print("開始遊戲") for i in range(5): role.startGame() print(role) print("**************************************") if '__main__' == __name__: main()
1 建立遊戲角色 2 存檔中... 3 開始遊戲 4 損失生命值:13 5 經過關卡,金錢+56 6 經過關卡,消滅敵人43 7 [遊戲角色] 金錢數:56 消滅敵人數:43 已經過關卡:2 當前血量:87 8 ************************************** 9 損失生命值:3 10 經過關卡,金錢+23 11 經過關卡,消滅敵人23 12 [遊戲角色] 金錢數:79 消滅敵人數:66 已經過關卡:3 當前血量:84 13 ************************************** 14 人物死亡,通關失敗 15 [遊戲角色] 金錢數:79 消滅敵人數:66 已經過關卡:3 當前血量:0 16 ************************************** 17 遊戲角色死亡,請從新開始遊戲或者讀取存檔 18 讀取存檔... 19 [遊戲角色] 金錢數:0 消滅敵人數:0 已經過關卡:1 當前血量:100 20 ************************************** 21 損失生命值:4 22 經過關卡,金錢+47 23 經過關卡,消滅敵人25 24 [遊戲角色] 金錢數:47 消滅敵人數:25 已經過關卡:2 當前血量:96 25 **************************************
21.狀態模式
在State模式中,使用類來表示狀態。State的意思就是「狀態」。經過切換類來方便地改變對象的狀態。
當須要增長新的狀態時,修改代碼也很方便,須要添加新的類就行了。
__author__ = 'Cq' ''' 該實例以銀行金庫報警系統爲例子 有一個金庫,金庫與警報中心相連,金庫裏有警鈴和正常通話用的電話,金庫裏有時鐘(監視當前時間) 金庫只能在白天使用,白天使用金庫的話,會在報警中心留下記錄,晚上使用會向報警中心發送緊急事態通知 任什麼時候候均可以使用警鈴向報警中心發送緊急事態通知 任什麼時候候均可以使用電話,白天使用會呼叫報警中心,晚上使用只能向報警中心留言 ''' class State(object): ''' 白天或晚上的狀態抽象類 ''' def __new__(cls, *args, **kwargs): ''' 因爲狀態只有一種,不須要不少想用的狀態,這裏使用單例模式的方法 只使用一個實例化對象 ''' if not hasattr(cls, '_instance'): cls._instance = super(State, cls).__new__(cls) return cls._instance def doClock(self, context, hour): raise NotImplementedError def doUse(self): raise NotImplementedError def doAlarm(self): raise NotImplementedError def doPhone(self): raise NotImplementedError class DayState(State): ''' 狀態:白天 ''' def doClock(self, context, hour): if hour < 9 or 17 <= hour: context.changeState(NightState()) def doUse(self): print("\033[32;1m使用金庫(白天)\033[0m") def doAlarm(self): print("\033[32;1m按下警鈴(白天)\033[0m") def doPhone(self): print("\033[32;1m正常通話(白天)\033[0m") def __str__(self): return "[白天]" class NightState(State): ''' 狀態:晚上 ''' def doClock(self, context, hour): if 9 <= hour and hour < 17: context.changeState(DayState()) def doUse(self): print("\033[31;1m緊急:晚上使用金庫\033[0m") def doAlarm(self): print("\033[31;1m按下警鈴(晚上)\033[0m") def doPhone(self): print("\033[31;1m晚上的通話錄音\033[0m") def __str__(self): return "[晚上]" class Context(object): ''' 負責管理狀態和聯繫報警中心的接口 ''' def setClock(self, hour): raise NotImplementedError def changeState(self, state): raise NotImplementedError def callSecurityCenter(self, msg): raise NotImplementedError def recordLog(self, msg): raise NotImplementedError class ContetApi(Context): ''' 實現Context接口 ''' def __init__(self): self.state = NightState() self.textScreen = [] def setClock(self, hour): if hour < 10: print("如今的時間是", "0"+str(hour)+":00") else: print("如今的時間是", str(hour)+":00") self.state.doClock(self, hour) def changeState(self, state): print("從", self.state, "狀態變爲了", state, "狀態。", sep="") self.state = state def callSecurityCenter(self, msg): self.textScreen.append("call! "+msg+"\n") def recordLog(self, msg): self.textScreen.append("record ... "+msg+"\n") def main(): context = ContetApi() for hour in range(24): context.setClock(hour) if hour == 2 or hour == 23: print("-----------------------") context.state.doUse() context.callSecurityCenter("%sH 金庫被搶了" % hour) context.state.doAlarm() context.callSecurityCenter("%sH 警報自動拉響" % hour) context.state.doPhone() context.recordLog('%sH 很差了金庫被炸開了!呼叫支援' % hour) print("-----------------------") if hour == 12: print("-----------------------") context.state.doUse() context.callSecurityCenter("%sH 金庫使用中" % hour) context.state.doAlarm() context.callSecurityCenter("%sH 警報被拉響" % hour) context.state.doPhone() context.recordLog('%sH 有人搶劫銀行呼叫支援' % hour) print("-----------------------") print("今天的警報中心記錄") print(context.textScreen) if "__main__" == __name__: main()
1 如今的時間是 00:00 2 如今的時間是 01:00 3 如今的時間是 02:00 4 ----------------------- 5 緊急:晚上使用金庫 6 按下警鈴(晚上) 7 晚上的通話錄音 8 ----------------------- 9 如今的時間是 03:00 10 如今的時間是 04:00 11 如今的時間是 05:00 12 如今的時間是 06:00 13 如今的時間是 07:00 14 如今的時間是 08:00 15 如今的時間是 09:00 16 從[晚上]狀態變爲了[白天]狀態。 17 如今的時間是 10:00 18 如今的時間是 11:00 19 如今的時間是 12:00 20 ----------------------- 21 使用金庫(白天) 22 按下警鈴(白天) 23 正常通話(白天) 24 ----------------------- 25 如今的時間是 13:00 26 如今的時間是 14:00 27 如今的時間是 15:00 28 如今的時間是 16:00 29 如今的時間是 17:00 30 從[白天]狀態變爲了[晚上]狀態。 31 如今的時間是 18:00 32 如今的時間是 19:00 33 如今的時間是 20:00 34 如今的時間是 21:00 35 如今的時間是 22:00 36 如今的時間是 23:00 37 ----------------------- 38 緊急:晚上使用金庫 39 按下警鈴(晚上) 40 晚上的通話錄音 41 ----------------------- 42 今天的警報中心記錄 43 ['call! 2H 金庫被搶了\n', 'call! 2H 警報自動拉響\n', 'record ... 2H 很差了金庫被炸開了!呼叫支援\n', 'call! 12H 金庫使用中\n', 'call! 12H 警報被拉響\n', 'record ... 12H 有人搶劫銀行呼叫支援\n', 'call! 23H 金庫被搶了\n', 'call! 23H 警報自動拉響\n', 'record ... 23H 很差了金庫被炸開了!呼叫支援\n']
22.迭代器模式
Iterator模式用於在數據集合中按照順序遍歷集合。
使用該模式最重要的理由是,將遍歷與實現分離開來,進而自定製遍歷方法
__author__ = 'Cq' class Aggregate(object): ''' 表示集合的接口 ''' def iterator(self): raise NotImplementedError class Iterator(object): ''' 遍歷集合的接口 ''' def hasNext(self): raise NotImplementedError def next(self): raise NotImplementedError class Book(object): ''' 表示書的類 ''' def __init__(self, name): self.name = name def getName(self): return self.name class BookShelf(Aggregate): ''' 表示書架的類,用於存放書 ''' def __init__(self, max_size): self.max = max_size self.books = [None for i in range(self.max)] self.last = 0 def getBookAt(self, index): return self.books[index] def appendBook(self, book): self.books[self.last] = book self.last += 1 def getLength(self): return self.last def iterator(self): return BookShelfIterator(self) class BookShelfIterator(Iterator): ''' 遍歷書架的類 ''' def __init__(self, bookShelf): self.__bookShelf = bookShelf self.__index = 0 def hasNext(self): if self.__index < self.__bookShelf.getLength(): return True else: return False def next(self): book = self.__bookShelf.getBookAt(self.__index) self.__index += 1 return book def main(): # 實例化一個書架,大小爲10本書 bookShelf = BookShelf(10) bookShelf.appendBook(Book("《C語言從研發到脫髮》")) bookShelf.appendBook(Book("《C++從入門到放棄》")) bookShelf.appendBook(Book("《Java從跨平臺到跨行業》")) bookShelf.appendBook(Book("《Ios開發從入門到下架》")) bookShelf.appendBook(Book("《Android開發大全--從開始到轉行》")) bookShelf.appendBook(Book("《PHP由初學至搬磚》")) bookShelf.appendBook(Book("《黑客攻防:從入門到入獄》")) bookShelf.appendBook(Book("《MySql從刪庫到跑路》")) bookShelf.appendBook(Book("《服務器運維管理從網絡異常到硬盤全紅》")) bookShelf.appendBook(Book("《服務器運維管理從網維到網管》")) it = bookShelf.iterator() while it.hasNext(): book = it.next() print(book.getName()) if '__main__' == __name__: main()
1 《C語言從研發到脫髮》 2 《C++從入門到放棄》 3 《Java從跨平臺到跨行業》 4 《Ios開發從入門到下架》 5 《Android開發大全--從開始到轉行》 6 《PHP由初學至搬磚》 7 《黑客攻防:從入門到入獄》 8 《MySql從刪庫到跑路》 9 《服務器運維管理從網絡異常到硬盤全紅》 10 《服務器運維管理從網維到網管》
23.解釋器模式
在Interpreter模式中,程序要解決的問題會被用很是簡單的「迷你語言」表述出來,即用「迷你語言」編寫的「迷你程序」把具體的問題表述出來。 迷你程序是沒法單獨工做的,咱們還須要用編程語言編寫一個負責「編譯」的程序。 翻譯程序會理解迷你語言,並解釋和運行迷你程序,這段翻譯程序也被稱爲解釋器。 遙控汽車運動爲例: go 爲前行1米 right 爲原地向右轉彎90° left 爲原地向左轉彎90° 迷你語言程序示例 program go end 小車前行1米中止 program go right right go end 小車前行1米,而後右轉兩次,前行1米中止 軌跡爲邊長爲1米的正方形 program repeat 4 go right end end 軌跡爲鋸齒狀 program repeat 4 repeat 3 go right go left end end end 解釋器中解釋器須要解釋的迷你語言語法 <program> ::= program <command list> <command list> ::= <command>* end <command> ::= <repeat command> | <primitive command> <repeat command> ::= repeat <number> <command list> <primitive command> ::= go | right | left
__author__ = 'Cq' ''' 經過編寫一段迷你程序的解釋器實現解釋器模式 如下是命令解釋: <program> ::= program <command list> <program>是程序定義字符 program關鍵字後面跟着的命令列表<command list> ::= 的左邊表示定義的名字,右邊表示定義的內容 <command list> ::= <command>* end <command list>是指重複0次以上<command>後,接着一個end關鍵字 '*'表示前面的內容循環0次以上 <command> ::= <repeat command> | <primitive command> <command>是指<repeat command>或<primitive command> <repeat command> ::= repeat <number><command list> <repeat command>是指repeat關鍵字後面跟着循環次數和循環命令列表 <command>中能夠出現<command list>,反之也能夠出現,這稱爲遞歸定義 <primitive command> 它指go或right或left <number> 即重複次數,天然數 ''' import sys import re class Node(object): ''' 表示語法樹「節點」的類 ''' def parse(self, context): raise NotImplementedError class ProgramNode(Node): ''' 對應處理<program>的類 ''' def __init__(self): self.commandListNode = None def parse(self, context): context.skipToken("program") self.commandListNode = CommandListNode() self.commandListNode.parse(context) def __str__(self): return "[ program "+self.commandListNode.__str__()+"]" class CommandListNode(Node): ''' 對應處理<command list>的類 ''' def __init__(self): self.list1 = [] def parse(self, context): while True: if context.currentToken() == None: print("Missing 'end'") sys.exit(0) elif context.currentToken() == "end": context.skipToken("end") break else: commandNode = CommandNode() commandNode.parse(context) self.list1.append(commandNode) def __str__(self): string = "" for node in self.list1: string += node.node.__str__() return string class CommandNode(Node): ''' 對應處理<command>的類 ''' def __init__(self): self.node = None def parse(self, context): if context.currentToken() == "repeat": self.node = RepeatCommandNode() self.node.parse(context) else: self.node = PrimitiveCommandNode() self.node.parse(context) def __str__(self): return self.node class RepeatCommandNode(Node): ''' 對應處理<repeat command>的類 ''' def __init__(self): self.number = None self.commandListNode = None def parse(self, context): context.skipToken("repeat") self.number = context.currentNumber() context.nextToken() self.commandListNode = CommandListNode() self.commandListNode.parse(context) def __str__(self): return "[ repeat "+str(self.number)+" "+self.commandListNode.__str__()+"] " class PrimitiveCommandNode(Node): ''' 對應處理<primitive command>的類 ''' def __init__(self): self.name = None def parse(self, context): self.name = context.currentToken() context.skipToken(self.name) if self.name != "go" and self.name != "right" and self.name != "left": print(self.name, "is undefined") def __str__(self): return self.name+" " class Context(object): def __init__(self, text, index=0): self.__currentToken = None # 存放當前命令名例:program self.__tokenizer = text # 存放整條迷你命令例:program end self.index = index # 當前獲取到第幾條命令例:program end 若是當前獲取到end,則index=2 self.nextToken() def nextToken(self): if self.hasMoreToken(self.__tokenizer): self.__currentToken = self.getNextToken(self.__tokenizer) else: self.__currentToken = None return self.__currentToken def hasMoreToken(self, tokenizer): res = False find_list = re.findall("(\w*?\s)", tokenizer) if self.index < len(find_list): res = True return res def getNextToken(self, tokenizer): find_list = re.findall("(\w*?\s)", tokenizer) res = find_list[self.index] temp = list(res) res = "".join(temp[0:-1]) self.index += 1 return res def currentToken(self): return self.__currentToken def skipToken(self, token): if token != self.__currentToken: print("Warning: "+token+" is expected,but ", self.__currentToken, " is found.") sys.exit(0) self.nextToken() def currentNumber(self): number = 0 try: number = int(self.__currentToken) except Exception as e: print("Warning: ", e) return number def main(): file = open("program.txt", 'r') for i in file.readlines(): print("text = ", i) node = ProgramNode() node.parse(Context(i)) print("node =", node) print("--------------------") file.close() if '__main__' == __name__: main()
1 text = program end 2 3 node = [ program ] 4 -------------------- 5 text = program go end 6 7 node = [ program go ] 8 -------------------- 9 text = program go right go right go right go right end 10 11 node = [ program go right go right go right go right ] 12 -------------------- 13 text = program repeat 4 go right end end 14 15 node = [ program [ repeat 4 go right ] ] 16 -------------------- 17 text = program repeat 4 repeat 3 go right go left end right end end 18 19 node = [ program [ repeat 4 [ repeat 3 go right go left ] right ] ] 20 --------------------
參考書籍:《圖解設計模式》
參考博客:http://www.cnblogs.com/alex3714/articles/5760582.html