参考博客 《大话设计模式》Python版代码实现 二十三种设计模式及其python实现html
设计模式(Design Patterns)python
——可复用面向对象软件的基础算法
设计模式(Design pattern)是一套被反复使用、多数人知晓的、通过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石同样。项目中合理的运用设计模式能够完美的解决不少问题,每种模式在如今中都有相应的原理来与之对应,每个模式描述了一个在咱们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被普遍应用的缘由。shell
Christopher Alexander:“每个模式描述了一个在咱们周围不断重复发生的问题,以及该问题的解决方案的核心。这样你就能一次又一次地使用该方案而没必要作重复劳动。”每个设计模式系统地命名、解释和评价了面向对象系统中一个重要的和重复出现的设计。编程
设计模式四个基本要素:模式名称、问题、解决方案、效果设计模式
经典的《设计模式》一书概括出23种设计模式,这23种模式又可归为,建立型、结构型和行为型3大类微信
2.1.建立型模式数据结构
前面讲过,社会化的分工愈来愈细,天然在软件设计方面也是如此,所以对象的建立和对象的使用分开也就成为了必然趋势。由于对象的建立会消耗掉系统的不少资源,因此单独对对象的建立进行研究,从而可以高效地建立对象就是建立型模式要探讨的问题。这里有6个具体的建立型模式可供研究,它们分别是:架构
简单工厂模式(Simple Factory);app
工厂方法模式(Factory Method);
抽象工厂模式(Abstract Factory);
建立者模式(Builder);
原型模式(Prototype);
单例模式(Singleton)。
说明:严格来讲,简单工厂模式不是GoF总结出来的23种设计模式之一。
依赖于继承的建立型模式:工厂方法模式
依赖于组合的建立性模式:抽象工厂模式、建立者模式
2.2 结构型模式
在解决了对象的建立问题以后,对象的组成以及对象之间的依赖关系就成了开发人员关注的焦点,由于如何设计对象的结构、继承和依赖关系会影响到后续程序的维护性、代码的健壮性、耦合性等。对象结构的设计很容易体现出设计人员水平的高低,这里有7个具体的结构型模式可供研究,它们分别是:
适配器模式(Adapter);
桥模式(Bridge);
组合模式(Composite);
装饰模式(Decorator);
外观模式(Facade);
享元模式(Flyweight)
代理模式(Proxy);
2.3 行为型模式
在对象的结构和对象的建立问题都解决了以后,就剩下对象的行为问题了,若是对象的行为设计的好,那么对象的行为就会更清晰,它们之间的协做效率就会提升,这里有11个具体的行为型模式可供研究,它们分别是:
解释器模式(Interpreter)。
责任链模式(Chain of Responsibility);
命令模式(Command);
迭代器模式(Iterator);
中介者模式(Mediator);
备忘录模式(Memento);
观察者模式(Observer);
状态模式(State);
策略模式(Strategy);
访问者模式(Visitor);
模板方法模式(Template Method);
一、开闭原则(Open Close Principle)
开闭原则就是说:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。即软件实体应尽可能在不修改原有代码的状况下进行扩展。在程序须要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。因此一句话归纳就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,咱们须要使用接口和抽象类,后面的具体设计中咱们会提到这点。
二、里氏替换原则(Liskov Substitution Principle)
里氏替换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类能够出现的地方,子类必定能够出现。及全部引用基类(父类)的地方必须能透明地使用其子类的对象。LSP是继承复用的基石,只有当衍生类能够替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也可以在基类的基础上增长新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,因此里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科
三、依赖倒置原则(Dependence Inversion Principle)
这个是开闭原则的基础,高层模块不该该依赖低层模块,两者都应该依赖其抽象;抽象不该该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程。具体内容:是对接口编程,依赖于抽象而不依赖于具体。
四、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。仍是一个下降类之间的耦合度的意思,从这儿咱们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。总结归纳:使用多个专门的接口,而不使用单一的总接口,即客户端不该该依赖那些它不须要的接口;下降依赖,下降耦合。
五、迪米特法则(最少知道原则)(Demeter Principle)
为何叫最少知道原则,就是说:一个实体应当尽可能少的与其余实体之间发生相互做用,使得系统功能模块相对独立。
六、单一职责原则:
不要存在多于一个致使类变动的缘由。通俗的说,即一个类只负责一项职责。
面向对象三大特性:封装,继承,多态
封装:
一、把数据和函数包装在类里
二、类的边界限制了一些外界的访问 ---》 私有属性
继承:解决代码复用 重写方法叫作:override 重写,复写
多态:父类能够表明子类
抽象类:
抽象类不能被实例化
抽象类的抽象方法,必须在子类中实现
接口:
一种特殊的类,声明了若干方法,要求继承该接口的类必须实现这些方法。
做用:限制继承接口的类的方法的名称及调用方式;隐藏了类的内部实现。
接口就是一种抽象的基类(父类),限制继承它的类必须实现接口中定义的某些方法
from abc import abstractmethod, ABCMeta #定义抽象类 class Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): """支付方法,参数money,每一个继承的类都要实现这个方法""" pass #实现Payment接口 class Alipay(Payment): def pay(self, money): print("支付宝支付%s元"%money) class ApplePay(Payment): def pay(self, money): print("苹果支付%s元"%money) class WechatPay(Payment): def pay(self, money): print("微信支付%s元"%money) def func(x): x.pay(100)
一、简单工厂模式
建立对象放在了工厂类中,而不是再暴露在外边,经过工厂类实现全部操做。
from abc import abstractmethod, ABCMeta #定义支付方法的抽象类 class Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): pass #定义不一样的支付方法 class Alipay(Payment): def __init__(self, enable_yuebao=False): self.enable_yuebao = enable_yuebao def pay(self, money): if self.enable_yuebao: print("余额宝支付%s元" % money) else: print("支付宝支付%s元" % money) class ApplePay(Payment): def pay(self, money): print("苹果支付%s元" % money) #简单工厂模式,一个工厂定义一个生产方式。经过传入的参数判断,不一样的支付类型 class PaymentFactory: def create_payment(self, method): if method == "alipay": return Alipay() elif method == "applepay": return ApplePay() elif method == "yuebao": return Alipay(enable_yuebao=True) else: raise NameError(method) f = PaymentFactory() p = f.create_payment("alipay") p.pay(100)
二、工厂方法模式
具体工厂依赖具体产品
内容:定义一个用于建立对象的接口(工厂接口),让子类决定实例化哪个产品类。
角色:
抽象工厂角色(Creator)
具体工厂角色(Concrete Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
模式特色:定义一个用于建立对象的接口,让子类决定实例化哪个类。这使得一个类的实例化延迟到其子类。
这个模式和简单工厂有区别,简单工厂模式只有一个工厂,工厂方法模式相比简单工厂模式将每一个具体产品都对应了一个具体工厂。
适用场景:
须要生产多种、大量复杂对象的时候
须要下降耦合度的时候
当系统中的产品种类须要常常扩展的时候
优势:
每一个具体产品都对应一个具体工厂类,不须要修改工厂类代码
隐藏了对象建立的实现细节
缺点:
每增长一个具体产品类,就必须增长一个相应的具体工厂类
内容:不直接向客户端暴露对象建立的实现细节,而是经过一个工厂类来负责建立产品类的实例。
角色:
工厂角色(Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
优势:
隐藏了对象建立的实现细节,工厂根据条件产生不一样功能的类。
客户端不须要修改代码
缺点:
违反了单一职责原则,将建立逻辑几种到一个工厂类里
当添加新产品时,须要修改工厂类代码,违反了开闭原则
from abc import abstractmethod, ABCMeta #定义支付类型的抽象类 class Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): pass #继承支付抽象类 class Alipay(Payment): def pay(self, money): print("支付宝支付%s元" % money) class ApplePay(Payment): def pay(self, money): print("苹果支付%s元"%money) #定义工厂的抽象类,用于支付类的生产 class PaymentFactory(metaclass=ABCMeta): @abstractmethod def create_payment(self): pass #继承工厂抽象类,具体工厂负责具体的产品 class AlipayFactory(PaymentFactory): def create_payment(self): return Alipay() class ApplePayFactory(PaymentFactory): def create_payment(self): return ApplePay() #具体使用,利用具体工厂的对象 实例 具体支付的对象 而后 调用支付方法 # 用户输入 # 支付宝,120 af = AlipayFactory() ali = af.create_payment() ali.pay(120)
三、抽象工厂模式
意图:提供一个建立一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
适用性:
一个系统要独立于它的产品的建立、组合和表示时。
一个系统要由多个产品系列中的一个来配置时。
当你要强调一系列相关的产品对象的设计以便进行联合使用时。
当你提供一个产品类库,而只想显示它们的接口而不是实现时。
内容:定义一个工厂类接口,让工厂子类来建立一系列相关或相互依赖的对象。
例:生产一部手机,须要手机壳、CPU、操做系统三类对象进行组装,其中每类对象都有不一样的种类。对每一个具体工厂,分别生产一部手机所须要的三个对象。
角色:
抽象工厂角色(Creator)
具体工厂角色(Concrete Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
客户端(Client)
相比工厂方法模式,抽象工厂模式中的每一个具体工厂都生产一套产品。
适用场景:
系统要独立于产品的建立与组合时
强调一系列相关的产品对象的设计以便进行联合使用时
提供一个产品类库,想隐藏产品的具体实现时
优势:
将客户端与类的具体实现相分离
每一个工厂建立了一个完整的产品系列,使得易于交换产品系列
有利于产品的一致性(即产品之间的约束关系)
缺点:
难以支持新种类的(抽象)产品
from abc import abstractmethod, ABCMeta # ------抽象产品------ class PhoneShell(metaclass=ABCMeta): @abstractmethod def show_shell(self): pass class CPU(metaclass=ABCMeta): @abstractmethod def show_cpu(self): pass class OS(metaclass=ABCMeta): @abstractmethod def show_os(self): pass # ------抽象工厂------ class PhoneFactory(metaclass=ABCMeta): @abstractmethod def make_shell(self): pass @abstractmethod def make_cpu(self): pass @abstractmethod def make_os(self): pass # ------具体产品------ class SmallShell(PhoneShell): def show_shell(self): print("普通手机小手机壳") class BigShell(PhoneShell): def show_shell(self): print("普通手机大手机壳") class AppleShell(PhoneShell): def show_shell(self): print("苹果手机壳") class SnapDragonCPU(CPU): def show_cpu(self): print("骁龙CPU") class MediaTekCPU(CPU): def show_cpu(self): print("联发科CPU") class AppleCPU(CPU): def show_cpu(self): print("苹果CPU") class Android(OS): def show_os(self): print("Android系统") class IOS(OS): def show_os(self): print("iOS系统") # ------具体工厂------ class MiFactory(PhoneFactory): def make_cpu(self): return SnapDragonCPU() def make_os(self): return Android() def make_shell(self): return BigShell() class HuaweiFactory(PhoneFactory): def make_cpu(self): return MediaTekCPU() def make_os(self): return Android() def make_shell(self): return SmallShell() class IPhoneFactory(PhoneFactory): def make_cpu(self): return AppleCPU() def make_os(self): return IOS() def make_shell(self): return AppleShell() # ------客户端------ class Phone: def __init__(self, cpu, os, shell): self.cpu = cpu self.os = os self.shell = shell def show_info(self): print("手机信息:") self.cpu.show_cpu() self.os.show_os() self.shell.show_shell() # ------创造产品------ def make_phone(factory): cpu = factory.make_cpu() os = factory.make_os() shell = factory.make_shell() return Phone(cpu, os, shell) p1 = make_phone(HuaweiFactory()) p1.show_info()
四、建造者模式
意图:将一个复杂对象的构建与它的表示分离,使得一样的构建过程能够建立不一样的表示。
适用场景:
当建立复杂对象的算法(Director)应该独立于该对象的组成部分(Builder)以及它们的装配方式时
当构造过程容许被构造的对象有不一样的表示时(不一样Builder)。
角色:
抽象建造者(Builder)
具体建造者(Concrete Builder)
指挥者(Director)
产品(Product)
建造者模式与抽象工厂模式类似,也用来建立复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象
优势:
隐藏了一个产品的内部结构和装配过程
将构造代码与表示代码分开
能够对构造过程进行更精细的控制
from abc import abstractmethod, ABCMeta #------产品------ class Player: def __init__(self, face=None, body=None, arm=None, leg=None): self.face = face self.arm = arm self.leg = leg self.body = body def __str__(self): return "%s, %s, %s, %s" % (self.face, self.arm, self.body, self.leg) #------建造者------ class PlayerBuilder(metaclass=ABCMeta): @abstractmethod def build_face(self): pass @abstractmethod def build_arm(self): pass @abstractmethod def build_leg(self): pass @abstractmethod def build_body(self): pass @abstractmethod def get_player(self): pass # 建造生产的类 class BeautifulWomanBuilder(PlayerBuilder): def __init__(self): self.player = Player() def build_face(self): self.player.face = "漂亮脸蛋" def build_arm(self): self.player.arm="细胳膊" def build_body(self): self.player.body="细腰" def build_leg(self): self.player.leg="长腿" def get_player(self): return self.player # 用于生产 产品的类 class PlayerDirector: def build_player(self, builder): builder.build_body() builder.build_arm() builder.build_leg() builder.build_face() return builder.get_player() #客户端 director = PlayerDirector() builder = BeautifulWomanBuilder() p = director.build_player(builder) print(p)
五、单例模式
意图:建立一个类,保证一个类只有一个实例,并提供一个访问它的全局访问点。单例至关因而全局变量,内部的方法可能会被更改
角色:
单例(Singleton)
适用场景
当类只能有一个实例并且客户能够从一个众所周知的访问点访问它时;
当这个惟一实例应该是经过子类化可扩展的,而且客户应该无需更改代码就能使用一个扩展的实例时。
优势:
对惟一实例的受控访问
单例至关于全局变量,但防止了命名空间被污染
与单例模式功能类似的概念:全局变量、静态变量(方法)
class Singleton(object): def __new__(cls, *args, **kwargs): if not hasattr(cls, "_instance"): cls._instance = super(Singleton, cls).__new__(cls) return cls._instance class MyClass(Singleton): def __init__(self, name): self.name = name a = MyClass("a") print(a) print(a.name) b = MyClass('b') # print(b) print(b.name) b.name = 'xxx' # print(a) print(a.name)
单例模式: 单例模式 每次只实例化一个对象!造对象的过程是__new__方法,给对象传数据是__init__的方法,作成一个实例! 类无论怎样建立多个实例,对象都会以第一个实例为准 #方式一:文件导入,文件内建立一个对象,经过这个对象导入方法 #方式二:经过静态方法实例化对象 class Foo: # 定义静态变量实例 _instance = None def __init__(self): pass @staticmethod def get_instance(cls): if cls._instance: return cls._instance else: obj = cls() cls._instance = obj return obj #方式三: __new__ class Foo(object): _instance = None def __init__(self): pass def __new__(cls, *args, **kwargs): if cls._instance: return cls._instance else: obj = object.__new__(cls, *args, **kwargs) cls._instance = obj return obj 用途: - 自定义curb组件时,对于类构建的信息,仅需一个实例 - 发布文章,特殊字符的过滤: KindEditor
六、适配器模式
意图:将一个类的接口转换成客户但愿的另外一个接口。适配器模式使得本来因为接口不兼容而不能一块儿工做的那些类能够一块儿工做。
角色:
目标接口(Target)
待适配的类(Adaptee)
适配器(Adapter)
两种实现方式:
类适配器:使用多继承
对象适配器:使用组合
适用场景:
你想使用一个已经存在的类,而它的接口不符合你的要求;
你想建立一个能够复用的类,该类能够与其余不相关的类或不可预见的类(即那些接口可能不必定兼容的类)协同工做。
(对象适配器)想使用一些已经存在的子类,但不可能对每个都进行子类化以匹配它们的接口。对象适配器能够适配它的父类接口。
类适配器和对象适配器有不一样的权衡。
类适配器规则:
使用一个具体的Adapter类对Adaptee和Target进行匹配。结果是当咱们想要匹配一个类以及全部他的子类时,类Adapter将不能胜任工做。
使用Adapter能够重定义Adapter的部分行为,由于Adapter是Adaptee的一个子类。
仅仅引入一个对象,并不须要额外的指针以间接获得adaptee.
对象适配器规则:
容许一个Adapter与多个Adaptee -- 即Adaptee自己以及它的全部子类(若是有子类的话)一一同时工做。Adapter也能够一次给全部的Adaptee添加功能。
使得重定义 Adaptee 的行为比较困难。这须要生成Adaptee的子类而且使得 Adapter 引用这个子类而不是引用Adaptee自己。
from abc import abstractmethod, ABCMeta class Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): raise NotImplementedError class Alipay(Payment): def pay(self, money): print("支付宝支付%s元"%money) class ApplePay(Payment): def pay(self, money): print("苹果支付%s元"%money) #------待适配类------ class WechatPay: def huaqian(self, money): print("微信支付%s元"%money) #------类适配器------ class RealWeChatPay(Payment, WechatPay): def pay(self, money): return self.huaqian(money) #------对象适配器------ class PayAdapter(Payment): def __init__(self, payment): self.payment = payment #类的一个对象 def pay(self, money): return self.payment.huaqian(money) RealWeChatPay().pay(100) #PayAdapter(WechatPay()).pay(1000)
from abc import abstractmethod, ABCMeta class Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): """支付方法,参数money""" pass #实现Payment接口 class Alipay(Payment): def pay(self, money): print("支付宝支付%s元"%money) class ApplePay(Payment): def pay(self, money): print("苹果支付%s元"%money) class PaymentX(metaclass=ABCMeta): @abstractmethod def zhifu(self, money): """支付方法,参数money""" pass class WechatPay(PaymentX): def zhifu(self, money): print("微信支付%s元"%money) class CreditCardPay(PaymentX): def zhifu(self, money): print("信用卡支付%s元" % money) class PaypalPay(PaymentX): def zhifu(self, money): print("信用卡支付%s元" % money) #类适配器 class RealWechatPay(Payment, WechatPay): def pay(self, money): self.zhifu(money) p = RealWechatPay() p.pay(100) #对象适配器 class RealPay(Payment): def __init__(self, payment_cls): self.__a = payment_cls() def pay(self, money): self.__a.zhifu(money) def test_payment(p): p.pay(100) test_payment(RealPay(CreditCardPay))
七、组合模式
意图:将对象组合成树形结构以表示“部分-总体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具备一致性。
角色:
抽象组件(Component)
叶子组件(Leaf)
复合组件(Composite)
客户端(Client)
适用场景:
表示对象的“部分-总体”层次结构(特别是结构是递归的)
但愿用户忽略组合对象与单个对象的不一样,用户统一地使用组合结构中的全部对象
优势:
定义了包含基本对象和组合对象的类层次结构
简化客户端代码,即客户端能够一致地使用组合对象和单个对象
更容易增长新类型的组件
缺点:
很难限制组合中的组件
from abc import abstractmethod, ABCMeta class Graphic(metaclass=ABCMeta): @abstractmethod def draw(self): pass @abstractmethod def add(self, graphic): pass def getchildren(self): pass # 图元 class Point(Graphic): def __init__(self, x, y): self.x = x self.y = y def draw(self): print(self) def add(self, graphic): raise TypeError def getchildren(self): raise TypeError def __str__(self): return "点(%s, %s)" % (self.x, self.y) class Line(Graphic): def __init__(self, p1, p2): self.p1 = p1 self.p2 = p2 def draw(self): print(self) def add(self, graphic): raise TypeError def getchildren(self): raise TypeError def __str__(self): return "线段[%s, %s]" % (self.p1, self.p2) class Picture(Graphic): def __init__(self): self.children = [] def add(self, graphic): self.children.append(graphic) def getchildren(self): return self.children def draw(self): print("------复合图形------") for g in self.children: g.draw() print("------END------") pic1 = Picture() point = Point(2,3) pic1.add(point) pic1.add(Line(Point(1,2), Point(4,5))) pic1.add(Line(Point(0,1), Point(2,1))) pic2 = Picture() pic2.add(Point(-2,-1)) pic2.add(Line(Point(0,0), Point(1,1))) pic = Picture() pic.add(pic1) pic.add(pic2) pic.draw() pic1.draw() point.draw()
八、代理模式
意图:为其余对象提供一种代理以控制对这个对象的访问。在须要用比较通用和复杂的对象指针代替简单的指针的时候,使用Proxy模式。
角色:
抽象实体(Subject)
实体(RealSubject)
代理(Proxy)
适用场景:
远程代理:为远程的对象提供代理。一个对象在不一样的地址空间提供局部表明。
虚代理:根据须要建立很大的对象。
保护代理:控制对原始对象的访问,用于对象有不一样访问权限时。保护代理用于对象应该有不一样的访问权限的时候。例如,在Choices 操做系统[ CIRM93]中KemelProxies为操做系统对象提供了访问保护。
智能指引(Smart Reference )取代了简单的指针,它在访问对象时执行一些附加操做。 它的典型用途包括:对指向实际对象的引用计数,这样当该对象没有引用时,能够自动释放它。
优势:
远程代理:能够隐藏对象位于远程地址空间的事实
虚代理:能够进行优化,例如根据要求建立对象
保护代理:容许在访问一个对象时有一些附加的内务处理
当第一次引用一个持久对象时,将它装入内存。在访问一个实际对象前,检查是否已经锁定了它,以确保其余对象不能改变它。
from abc import ABCMeta, abstractmethod class Subject(metaclass=ABCMeta): @abstractmethod def get_content(self): pass def set_content(self, content): pass #文件操做,获取文件内容和设置 class RealSubject(Subject): def __init__(self, filename): self.filename = filename print("读取%s文件内容"%filename) f = open(filename) self.content = f.read() f.close() def get_content(self): return self.content def set_content(self, content): f = open(self.filename, 'w') f.write(content) self.content = content f.close() class ProxyA(Subject): def __init__(self, filename): self.subj = RealSubject(filename) def get_content(self): return self.subj.get_content() #---虚代理 class ProxyB(Subject): def __init__(self, filename): self.filename = filename self.subj = None def get_content(self): if not self.subj: self.subj = RealSubject(self.filename) return self.subj.get_content() x = ProxyB('abc.txt') """abc.txt 内文本 hello world""" #print(x.get_content()) # --保护代理 class ProxyC(Subject): def __init__(self, filename): self.subj = RealSubject(filename) def get_content(self): self.subj.get_content() def set_content(self, content): raise PermissionError filename = "abc.txt" username = input() if username!="somebody": p = ProxyC(filename) else: p = ProxyA(filename) print(p.get_content())
九、责任链模式
意图:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
角色:
抽象处理者(Handler)
具体处理者(ConcreteHandler)
客户端(Client)
适用场景:
有多个对象能够处理一个请求,哪一个对象处理由运行时决定
在不明确接收者的状况下,向多个对象中的一个提交一个请求
可处理一个请求的对象集合应被动态指定。
优势:
下降耦合度:一个对象无需知道是其余哪个对象处理其请求
缺点:
请求不保证被接收:链的末端没有处理或链配置错误
例:
请假部门批准:leader ---> 部门经理 ---> 总经理
Javascript事件浮升机制
from abc import ABCMeta, abstractmethod class Handler(metaclass=ABCMeta): @abstractmethod def handle_leave(self, day): pass class GeneralManagerHandler(Handler): def handle_leave(self, day): if day < 10: print("总经理批准%d天假"%day) else: print("呵呵") class DepartmentManagerHandler(Handler): def __init__(self): self.successor = GeneralManagerHandler() def handle_leave(self, day): if day < 7: print("部门经理批准%d天假"%day) else: print("部门经理无权准假") self.successor.handle_leave(day) class ProjectDirectorHandler(Handler): def __init__(self): self.successor = DepartmentManagerHandler() def handle_leave(self, day): if day < 3: print("项目主管批准%d天假"%day) else: print("项目主管无权准假") self.successor.handle_leave(day) day = 9 h = ProjectDirectorHandler() h.handle_leave(day)
class Handler(metaclass=ABCMeta): @abstractmethod def add_event(self, func): pass @abstractmethod def handle(self): pass class BodyHandler(Handler): def __init__(self): self.func = None def add_event(self, func): self.func = func def handle(self): if self.func: return self.func() else: print("已到最后一级,没法处理") class ElementHandler(Handler): def __init__(self, successor): self.func = None self.successor = successor def add_event(self, func): self.func = func def handle(self): if self.func: return self.func() else: return self.successor.handle() # 客户端 # <body><div><a> body = {'type': 'body', 'name': 'body', 'children': [], 'father': None} div = {'type': 'div', 'name': 'div', 'children': [], 'father': body} a = {'type': 'a', 'name': 'a', 'children': [], 'father': div} body['children'].append(div) div['children'].append(a) body['event_handler'] = BodyHandler() div['event_handler'] = ElementHandler(div['father']['event_handler']) a['event_handler'] = ElementHandler(a['father']['event_handler']) def attach_event(element, func): element['event_handler'].add_event(func) def func_div(): print("这是给div的函数") def func_a(): print("这是给a的函数") def func_body(): print("这是给body的函数") #attach_event(div, func_div) attach_event(a, func_a) attach_event(body, func_body) a['event_handler'].handle()
十、迭代器模式
意图:提供一种方法顺序访问一个聚合对象中的各个元素,而又不须要暴露该对象的内部表示
适用性:
访问一个聚合对象的内容而无需暴露它的内部表示。
支持对聚合对象的多种遍历。
为遍历不一样的聚合结构提供一个统一的接口(即, 支持多态迭代)。
实现方法:__iter__、__next__
class Range: def __init__(self,start,end): self.start = start self.end = end def __iter__(self): #将对象转变成迭代器 return self def __next__(self): #自取值 if self.start == self.end: raise StopIteration n = self.start self.start+=1 return n for i in Range(1,10): print(i)
十一、观察者模式
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 全部依赖于它的对象都获得通知并被自动更新。观察者模式又称“发布-订阅”模式
角色:
抽象主题(Subject)
具体主题(ConcreteSubject)——发布者
抽象观察者(Observer)
具体观察者(ConcreteObserver)——订阅者
适用场景:
当一个抽象模型有两方面,其中一个方面依赖于另外一个方面。将这二者封装在独立对象中以使它们能够各自独立地改变和复用。
当对一个对象的改变须要同时改变其它对象,而不知道具体有多少对象有待改变。
当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之,你不但愿这些对象是紧密耦合的。
优势:
目标和观察者之间的抽象耦合最小
支持广播通讯
缺点:
多个观察者之间互不知道对方存在,所以一个观察者对主题的修改可能形成错误的更新。
from abc import ABCMeta, abstractmethod class Observer(metaclass=ABCMeta): @abstractmethod def update(self, notice): pass class Notice: def __init__(self): self.observers = [] def attach(self, obs): self.observers.append(obs) def detach(self, obs): self.observers.remove(obs) obs.company_info=None def notify(self): for obj in self.observers: obj.update(self) class ManagerNotice(Notice): def __init__(self, company_info=None): super().__init__() self.__company_info = company_info @property def company_info(self): return self.__company_info @company_info.setter def company_info(self, info): self.__company_info = info self.notify() class Manager(Observer): def __init__(self): self.company_info = None def update(self, noti): self.company_info = noti.company_info notice = ManagerNotice() abes = Manager() dws = Manager() # print(alex.company_info) # print(wusir.company_info) notice.attach(abes) notice.attach(dws) # notice.company_info="公司运行良好" # # print(alex.company_info) # print(wusir.company_info) notice.company_info="公司将要上市" print(abes.company_info) print(dws.company_info) # notice.detach(dws) # # notice.company_info="公司要破产了,赶快跑路" # print(abes.company_info) print(dws.company_info)
十二、策略模式
意图:定义一系列的算法,把它们一个个封装起来,而且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
角色:
抽象策略(Strategy)
具体策略(ConcreteStrategy)
上下文(Context)
适用场景:
许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。
须要使用一个算法的不一样变体。例如,你可能会定义一些反映不一样的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时,可使用策略模式。
算法使用了客户端无需知道的数据。可以使用策略模式以免暴露复杂的、与算法相关的数据结构。
一个类中的多种行为以多个条件语句的形式存在,能够将这些行为封装如不一样的策略类中。
from abc import ABCMeta, abstractmethod import random class Sort(metaclass=ABCMeta): @abstractmethod def sort(self, data): pass class QuickSort(Sort): def quick_sort(self, data, left, right): if left < right: mid = self.partition(data, left, right) self.quick_sort(data, left, mid - 1) self.quick_sort(data, mid + 1, right) def partition(self, data, left, right): tmp = data[left] while left < right: while left < right and data[right] >= tmp: right -= 1 data[left] = data[right] while left < right and data[left] <= tmp: left += 1 data[right] = data[left] data[left] = tmp return left def sort(self, data): print("快速排序") return self.quick_sort(data, 0, len(data) - 1) class MergeSort(Sort): def merge(self, data, low, mid, high): i = low j = mid + 1 ltmp = [] while i <= mid and j <= high: if data[i] <= data[j]: ltmp.append(data[i]) i += 1 else: ltmp.append(data[j]) j += 1 while i <= mid: ltmp.append(data[i]) i += 1 while j <= high: ltmp.append(data[j]) j += 1 data[low:high + 1] = ltmp def merge_sort(self, data, low, high): if low < high: mid = (low + high) // 2 self.merge_sort(data, low, mid) self.merge_sort(data, mid + 1, high) self.merge(data, low, mid, high) def sort(self, data): print("归并排序") return self.merge_sort(data, 0, len(data) - 1) class Context: def __init__(self, data, strategy=None): self.data = data self.strategy = strategy def set_strategy(self, strategy): self.strategy = strategy def do_strategy(self): if self.strategy: self.strategy.sort(self.data) else: raise TypeError li = list(range(100000)) random.shuffle(li) context = Context(li, MergeSort()) context.do_strategy() #print(context.data) random.shuffle(context.data) context.set_strategy(QuickSort()) context.do_strategy()
1三、模板方法模式
意图:定义一个操做中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类能够不改变一个算法的结构便可重定义该算法的某些特定步骤。
角色:
抽象类(AbstractClass):定义抽象的原子操做(钩子操做);实现一个模板方法做为算法的骨架。
具体类(ConcreteClass):实现原子操做
适用场景:
一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
各个子类中的公共行为应该被提取出来并集中到一个公共父类中以免代码重复。
控制子类扩展。模板方法只在特定点调用某操做,这样就只容许在这些点进行扩展。
优势:
定义了一系列可重用的算法和行为
消除了一些条件语句
能够提供相同行为的不一样实现
缺点:
客户必须了解不一样的策略
策略与上下文之间的通讯开销
增长了对象的数目
from abc import ABCMeta, abstractmethod class IOHandler(metaclass=ABCMeta): @abstractmethod def open(self, name): pass @abstractmethod def deal(self, change): pass @abstractmethod def close(self): pass def process(self, name, change): self.open(name) self.deal(change) self.close() class FileHandler(IOHandler): def open(self, name): self.file = open(name,"w") def deal(self, change): self.file.write(change) def close(self): self.file.close() f = FileHandler() f.process("abc.txt", "Hello World")