什么是设计模式
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结
使用设计模式的目的
为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样
设计模式六大原则
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