设计模式是针对面向对象的,所谓的设计就是在编写程序以前对其有一个基础的架构,如须要建立哪些类,定义那些变量,有哪些方法。每个设计模式系统的命名、解释和评价了面向对象系统中一个重要和重复出现的设计。设计模式四个基本要素:模式名称、问题、解决方案、效果。python
面向对象的三大特性:算法
封装:封装指的是两方面 , 一方面把相关的功能概括到一个类中, 另外一方面把数据封装到对象中。shell
继承:继承就是为了提高代码的复用性,更加灵活。数据库
多态:多态指的是一个变量能够有多种状态或者多种形态。编程
接口:设计模式
本质是一个抽象类,要求继承接口的类,必须实现接口内定义的一些方法。微信
抽象类就是不能实例化的类。架构
若是继承抽象类后同样没有实现抽象方法,那么它也是一个抽象类。app
做用:限制继承接口的类的方法的名称及调用方式;隐藏了类的内部实现。框架
#在python中没有严谨的限制函数签名,只限制了函数名。 from abc import abstractmethod, ABCMeta class Interface(metaclass=ABCMeta): @abstractmethod def method(self, arg): pass
开闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。即软件实体应尽可能在不修改原有代码的状况下进行扩展。
里氏(Liskov)替换原则:全部引用基类(父类)的地方必须能透明地使用其子类的对象。
可以进行统一的调用,函数签名必须一致。
依赖倒置原则:高层模块不该该依赖低层模块,两者都应该依赖其抽象;抽象不该该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程。
A,B同时调用C模块,C模块进行修改,那么AB模块可能也须要修改,因此接口就是哪些东西不能改的限制,先有接口后又代码。
接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不该该依赖那些它不须要的接口。
若是不实现不须要的方法,那么就没法实例化,可使用多继承来继承多个小基类。
迪米特法则:一个软件实体应当尽量少地与其余实体发生相互做用。
解耦,让依赖越少,那么自由度越高。
单一职责原则:不要存在多于一个致使类变动的缘由。
通俗的说,即一个类只负责一项职责。
建立型模式:工厂方法模式,抽象工厂模式,建立者模式,原型模式,单例模式。结构型模式:适配器模式,桥模式,组合模式,装饰模式,外观模式,享元模式,代理模式。行为型模式:解释器模式,责任链模式,命令模式,迭代器模式,中介者模式,备忘录模式,观察者模式,状态模式,策略模式,模板方法模式。
建立型模式的重点在于如何建立一个对象。
简单工厂模式:
不直接向客户端暴露对象建立的实现细节,而是经过一个工厂类来负责建立产品类的实例。
角色:工厂角色,抽象产品角色,具体产品角色。
优势:隐藏了对象建立的实现细节,客户端不须要修改代码
缺点:
违反了单一职责原则,将建立逻辑集中到一个工厂类里。
当添加新产品时,须要修改工厂类代码,违反了开闭原则
from abc import abstractmethod, ABCMeta class Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): raise NotImplementedError class Alipay(Payment): def __init__(self, use_huabei=False): self.use_huabei = use_huabei def pay(self, money): if self.use_huabei: print("花呗支付%s元" % money) else: print("支付宝支付%s元" % money) class ApplePay(Payment): def __init__(self, s): pass 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 == 'huabei': return Alipay(use_huabei=True) else: raise NameError(method) pf = PaymentFactory() p = pf.create_payment('huabei') p.pay(100)
定义一个用于建立对象的接口(工厂接口),让子类决定实例化哪个产品类。
角色:抽象工厂角色,具体工厂角色,抽象产品角色,具体产品角色。
工厂方法模式拥有继承抽象工厂类的抽象工厂类。
使用场景:须要生产多种大量的对象的时候;须要下降耦合度的时候;当系统的产品种类须要扩展的时候。
优势: 每一个具体产品对应一个具体工厂类,隐藏了对象建立的细节。
缺点:每增长一个具体产品类,就要添加一个具体工厂类。
from abc import abstractmethod, ABCMeta class Payment(metaclass=ABCMeta): @abstractmethod def pay(self, money): raise NotImplementedError class Alipay(Payment): def __init__(self, use_huabei=False): self.use_huabei = use_huabei def pay(self, money): if self.use_huabei: print("花呗支付%s元" % money) else: 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(use_huabei=False) class ApplePayFactory(PaymentFactory): def create_payment(self): return ApplePay() class HuabeiFactory(PaymentFactory): def create_payment(self): return Alipay(use_huabei=True)
多个对象须要一块儿使用的时候使用,多个小对象组合成一个大对象。如面向对象中实现代码复用的组合。
角色:抽象工厂角色,具体工厂角色,抽象产品角色,具体产品角色,客户端。
抽象工厂模式中每一个具体工厂都生产一套产品。
适用场景:系统要独立于产品的建立与组合时;强调一系列相关的产品对象的设计以便进行联合使用时;提供一个产品类库,想隐藏产品的具体实现时。
优势:将客户端与类的具体实现相分离;每一个工厂建立了一个完整的产品系列,使得易于交换产品系列;有利于产品的一致性(即产品之间的约束关系)。
缺点:难以支持新种类的(抽象)产品
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(IPhoneFactory()) p1.show_info()
将一个复杂的对象的构建和它的表示分离,使一样的构建过程能够建立不一样的表示。
角色:抽象建造者,具体建造者,指挥者,产品。
建造者模式与抽象工厂模式类似,也用来建立复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。
适用场景:
当建立复杂对象的算法(Director)应该独立于该对象的组成部分以及它们的装配方式(Builder)时。
当构造过程容许被构造的对象有不一样的表示时(不一样Builder)。
优势:隐藏了一个产品的内部结构和装配过程;将构造代码与表示代码分开;能够对构造过程进行更精细的控制。
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 #无所谓beautfulbuilder编写的顺序 class PlayerDirector: def build_player(self, builder): builder.build_body() builder.build_face() builder.build_arm() builder.build_leg() return builder.get_player() pd = PlayerDirector() pb = BeautifulWomanBuilder() p = pd.build_player(pb) print(p)
保证一个类只有一个实例对象,并提供一个访问它的全局访问点,日志对象就是单例,数据库链接对象也是单例的。
适用场景:当类只能有一个实例并且客户能够从一个众所周知的访问点访问它时。
优势:对惟一实例的受控访问;单例至关于全局变量,但防止命名空间污染。
保证一个类只有一个实例对象,并提供一个访问它的全局访问点,日志对象就是单例,数据库链接对象也是单例的。适用场景:当类只能有一个实例并且客户能够从一个众所周知的访问点访问它时。优势:对惟一实例的受控访问;单例至关于全局变量,但防止命名空间污染。
from abc import abstractmethod, ABCMeta 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=None): if name is not None: self.name = name a = MyClass("a") print(a) print(a.name) b = MyClass("b") print(b) print(b.name) print(a) print(a.name)
当两个类不能一块儿使用,那么增长一些方法使它们可以一块儿使用,这就叫适配器模式。类适配器处理多个待适配类时,十分麻烦,因此经过组合来写适配器,也就是对象适配器,会更好。
将一个类的接口转换成客户但愿的另外一个接口。适配器模式使得本来因为接口不兼容而不能一块儿工做的那些类能够一块儿工做。
角色:目标接口,待适配的类,适配器。
实现方式:类适配器,对象适配器。
适用场景:想使用一个已经存在的类,而它的接口不符合你的要求;(对象适配器)想使用一些已经存在的子类,但不可能对每个都进行子类化以匹配它们的接口。对象适配器能够适配它的父类接口。)
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 BankPay: def huaqian(self, money): print("银行卡支付%s元" % money) # # 类适配器 # class NewWechatPay(WechatPay, Payment): # def pay(self, money): # self.huaqian(money) # 对象适配器 class PaymentAdapter(Payment): def __init__(self, p): self.payment = p def pay(self, money): self.payment.huaqian(100) p = PaymentAdapter(BankPay()) p.pay(100)
为其余对象提供一种代理以控制对这个对象的访问。角色:抽象实体,实体,代理。使用场景:
远程代理:为远程的对象提供代理。
虚代理:根据须要建立很大的对象。
保护代理:控制对原始对象的访问,用于对象有不一样访问权限时。优势:
远程代理:能够隐藏对象位于远程地址空间的事实。
虚代理:能够进行优化,例如根据要求建立对象。
保护代理:容许在访问一个对象时有一些附加的内务处理。
from abc import ABCMeta, abstractmethod class Subject(metaclass=ABCMeta): @abstractmethod def get_content(self): pass class RealSubject(Subject): def __init__(self, filename): print("读取%s文件内容"%filename) f = open(filename) self.content = f.read() f.close() def get_content(self): return self.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() p = ProxyB("abc.txt")
将对象组合成树形结构以表示“部分-总体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具备一致性。角色:抽象组件,叶子组件,复合组件,客户端。适用场景:
表示对象的“部分-总体”层次结构(特别是结构是递归的)
但愿用户忽略组合对象与单个对象的不一样,用户统一地使用组合结构中的全部对象
缺点:很难限制组合中的组件。
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() pic1.add(Point(2,3)) 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) pic1.draw()
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 全部依赖于它的对象都获得通知并被自动更新。观察者模式又称“发布-订阅”模式。
角色:
优势:目标和观察者之间的抽象耦合最小。
缺点:多个观察者之间互不知道对方存在,所以一个观察者对主题的修改可能形成错误的更新。
适用场景:
当对一个对象的改变须要同时改变其它对象,而不知道具体有多少对象有待改变。
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) 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
定义一系列的算法,把它们一个个封装起来,而且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
优势:定义了一系列可重用的算法和行为;消除了一些条件语句;提供行为的不一样实现。
缺点:客户必须了解所有策略;
适用场景:
class Sort(metaclass=ABCMeta): @abstractmethod def sort(self, data): pass class Merge_sort(Sort): def sort(self, data): pass class Quick_sort(Sort): def sort(self, data): pass 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
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
角色:抽象处理者,具体处理者,客户端。
使用场景:
优势:下降耦合度,不须要知道是那个对象处理的请求。
缺点:请求不能保证必定被接受。
from abc import ABCMeta, abstractmethod class Handler(metaclass=ABCMeta): @abstractmethod def handle_leave(self, day): pass class GeneralManagerliHandler(Handler): def handle_leave(self, day): if day < 10: print("总经理批准%d天假"%day) else: print("呵呵") class DepartmentManagerHandler(Handler): def __init__(self): self.successor = GeneralManagerliHandler() 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天假") else: print("项目主管无权准假") self.successor.handle_leave(day) day = 10 h = ProjectDirectorHandler() h.handle_leave(day)
模板方法模式
定义一个操做中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类能够不改变一个算法的结构便可重定义该算法的某些特定步骤。如市面上的一些框架。
角色:
适用场景:
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()