赞
踩
设计模式:对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。每一个设计模式系统地命名、解释和评价了面向对象系统中一个重要的和重复出现的设计。
面向对象的三大特性:
封装
继承
多态
这三大特性顺序不能错,因为他们之间不是并列关系而是递进关系。
接口:若干抽象方法的集合。
作用:限制实现接口的类必须按照接口给定的调用方式实现这些方法;对高层模块隐藏了类的内部实现。
代码示例:
# 接口方法一: # class Payment: # def pay(self,money): # raise NotImplementedError # 抛出一个没有实现错误,要求继承Payment的类必须实现pay方法 # 接口方法二:常用 from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): # abc: abstract class @abstractmethod def pay(self,money): pass class Alipay(Payment): def pay(self, money): print('支付宝支付%d元' % money) class WechatPay(Payment): def pay(self,money): print('微信支付%d元' % money) # p = Alipay() p = WechatPay() p.pay(100)
如果一个类里有抽象方法,那么该类就是一个抽象类。上述代码中Payment类有抽象方法def pay(),所以Payment是一个抽象类。
上述代码的Alipay类和Wechat类就算底层代码,对类的调用p.pay(100)就属于高层代码(模块),如果有了接口进行限制,编写高层代码的人只需要读懂接口就可以正确调用函数,而不必把底层的每个类是如何实现的挨个看一遍。
单一职责原则(Single Responsibility Principle):不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
开放封闭原则(Open Closed Principle):一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
里氏替换原则(Liskov Substitution Principle):所有引用父类的地方必须能透明地使用其子类的对象。
接口隔离原则(Interface-Segregation Principles):使用多个专门的接口,而不使用单一的总接口,即客户端(高层模块)不应该依赖那些它不需要的接口。
解释:设计模式中客户端的概念通常是指高层代码(模块),并不是网络通信server、client概念下的客户端。
依赖倒置原则(Dependence Inversion Principle):高层模块不应该依赖底层模块,二者都应该依赖其抽象(即接口);抽象不应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程。
解释:这样如果底层代码进行了改动,高层代码(模块)则不用随之改动。抽象就是上述代码的class Payment接口,细节就是class Alipay和class WechatPay,应该是先定义好接口,然后根据接口规则去实现细节;不能先写好细节,根据细节去定义接口。
代码示例:
# 接口隔离原则 class LandAnimal(metaclass=ABCMeta): # 专门的接口(陆地) @abstractmethod def walk(self): pass class WaterAnimal(metaclass=ABCMeta): # 专门的接口(水上) @abstractmethod def swim(self): pass class SkyAnimal(metaclass=ABCMeta): # 专门的接口(天上) @abstractmethod def fly(self): pass class Tiger(LandAnimal): def walk(self): print("老虎走路") class Frog(LandAnimal,WaterAnimal): def walk(self): print("青蛙走路") def swim(self): print("青蛙游泳")
简单工厂模式不属于23种设计模式。
内容:不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。
角色:
工厂角色(Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
代码示例:
# 简单工厂模式 from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): # 抽象产品角色 # abc: abstract class @abstractmethod def pay(self,money): pass class Alipay(Payment): # 具体产品角色 def __init__(self, use_huabei=False): self.use_huabei = use_huabei def pay(self, money): if self.use_huabei: print('花呗支付%d元' % money) else: print('支付宝余额支付%d元' % money) class WechatPay(Payment): # 具体产品角色 def pay(self,money): print('微信支付%d元' % money) class PaymentFactor: # 工厂角色 def creat_payment(self,method): if method == 'alipay': return Alipay() elif method == 'wechat': return WechatPay() elif method == 'huabei': return Alipay(use_huabei=True) else: raise TypeError("No such payment named %s" % method) # client (高层代码模块) pf = PaymentFactor() p = pf.creat_payment('huabei') p.pay(100)
内容:定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类。
角色:
抽象工厂角色(Creator)
具体工厂角色(Concrete Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
代码示例:
# 工厂方法模式 from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): # 抽象产品角色 # abc: abstract class @abstractmethod def pay(self,money): pass class Alipay(Payment): # 具体产品角色 def __init__(self, use_huabei=False): self.use_huabei = use_huabei def pay(self, money): if self.use_huabei: print('花呗支付%d元' % money) else: print('支付宝余额支付%d元' % money) class WechatPay(Payment): # 具体产品角色 def pay(self,money): print('微信支付%d元' % money) class BankPay(Payment): # 具体产品角色 def pay(self,money): print('银行卡支付%d元' % money) class PaymentFactory(metaclass=ABCMeta): # 抽象工厂角色 @abstractmethod def creat_payment(self): pass class AlipayFactory(PaymentFactory): # 具体工厂角色 def creat_payment(self): return Alipay() class WechatpayFactory(PaymentFactory): # 具体工厂角色 def creat_payment(self): return WechatPay() class HuabeiFactory(PaymentFactory): # 具体工厂角色 def creat_payment(self): return Alipay(use_huabei=True) class BankPayFactory(PaymentFactory): # 具体工厂角色 def creat_payment(self): return BankPay() # client (高层代码模块) pf = HuabeiFactory() p = pf.creat_payment() p.pay(100)
优点:
缺点:
每增加一个具体产品类,就必须增加一个相应的具体工厂类。
内容:定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象。
例:生产一部手机,需要手机壳、CPU、操作系统三类对象进行组装,其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象。
相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一套产品。
角色:
抽象工厂角色(Creator)
具体工厂角色(Concrete Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
客户端(Client)
代码示例:
# 抽象工厂模式 from abc import ABCMeta, abstractmethod # ------抽象产品-------- 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("Apple A13 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() # client (高层代码模块) 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()
优点:
缺点:
难以支持新种类的(抽象)产品。
内容:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。下例中漂亮女孩和怪兽就是不同的表示,PlayerDirector就是同样的构建过程。
角色:
抽象建造者(Builder)
具体建造者(Concrete Builder)
指挥者(Director)
产品(Product)
代码示例:
# 建造者模式 from abc import ABCMeta, abstractmethod class Player: # 产品 def __init__(self, face=None, body=None, arm=None, leg=None): self.face = face self.body = body self.arm = arm self.leg = leg def __str__(self): return "%s, %s, %s, %s" % (self.face, self.body,self.arm, self.leg) class PlayerBuilder(metaclass=ABCMeta): # 抽象建造者 @abstractmethod def build_face(self): pass @abstractmethod def build_body(self): pass @abstractmethod def build_arm(self): pass @abstractmethod def build_leg(self): pass # 表示代码: class SexyGirlBuilder(PlayerBuilder): # 具体建造者 def __init__(self): self.player = Player() def build_face(self): self.player.face = "漂亮脸蛋" def build_body(self): self.player.body = "好身材" def build_arm(self): self.player.arm = "漂亮胳膊" def build_leg(self): self.player.leg = "大长腿" # 表示代码: class Monster(PlayerBuilder): # 具体建造者 def __init__(self): self.player = Player() def build_face(self): self.player.face = "怪兽脸" def build_body(self): self.player.body = "怪瘦身" def build_arm(self): self.player.arm = "长毛的胳膊" def build_leg(self): self.player.leg = "长毛的腿" # 构造代码: class PlayerDirector: # 指挥者:控制组装顺序 身子-脸-胳膊-腿 def build_player(self, builder): builder.build_body() builder.build_face() builder.build_arm() builder.build_leg() return builder.player # client (高层代码模块) builder = SexyGirlBuilder() director = PlayerDirector() p = director.build_player(builder) print(p)
建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。
优点:
内容:保证一个类只有一个实例,并提供一个访问它的全局访问点。
角色:
单例(Singleton)
代码示例:
# 单例模式 class Singleton: def __new__(cls, *args, **kwargs): # 用于在__init__之前,给整个对象初始化 if not hasattr(cls, "_instance"): # 如果这个类没有_instance属性 cls._instance = super(Singleton, cls).__new__(cls) # 则调用父类(Object)的__new__方法创建 return cls._instance class MyClass(Singleton): def __init__(self, a): self.a = a """本句执行时,先执行Singleton类的__new__方法,发现没有_instance属性,则调用父类__new__方法 创建一个实例,返回MyClass._instance,接着执行MyClass类的__init__方法,赋值self.a = 10""" a = MyClass(10) """本句执行时,先执行Singleton类的__new__方法,发现有_instance属性,直接返回MyClass._instance, 接着执行MyClass类的__init__方法,赋值self.a = 20,把上面的10覆盖掉了""" b = MyClass(20) print(a.a) # 20 print(b.a) # 20 print(id(a),id(b)) # 2327807218520 2327807218520
优点:
对唯一实例的受控访问。
单例相当于全局变量,但防止了命名空间被污染。
解释:全局变量定义了就占用一个变量名,后面都无法使用该变量名;而单例的变量名用完了可以重新实例化赋给一个新的变量名。
使用场景不多,略
内容:将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
两种实现方式:
类适配器:使用多继承
对象适配器:使用组合
面向对象里的组合:
# 组合:在一个类里放入另外一个类的对象
class A:
pass
class B:
def __init__(self):
self.a = A()
代码示例:
# 适配器模式 from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): # 目标接口 # abc: abstract class @abstractmethod def pay(self,money): pass class Alipay(Payment): def pay(self, money): print('支付宝支付%d元' % money) class WechatPay(Payment): def pay(self,money): print('微信支付%d元' % money) class BankPay: # 待适配的类 def cost(self,money): print('银联支付%d元' % money) class ApplePay: # 待适配的类 def cost(self,money): print('苹果支付%d元' % money) # 类适配器(多继承):每一个想要适配的类都得写一个对应的类适配器 # class NewBankPay(Payment, BankPay): # def pay(self, money): # self.cost(money) # 对象适配器(组合):只用写一个适配器,就可以适配多个类 class PaymentAdapter(Payment): def __init__(self,payment): self.payment = payment def pay(self,money): self.payment.cost(money) p = PaymentAdapter(ApplePay()) p.pay(100)
角色:
目标接口(Target)
待适配的类(Adaptee)
适配器(Adapter)
适用场景:
内容:将一个事物的两个维度分离,使其都可以独立地变化。下例中的两个维度分别是形状和颜色。
角色:
抽象(Abstraction)
细化抽象(RefinedAbstraction)
实现者(Implementor)
具体实现者(Concretelmplementor)
代码示例:
# 继承的方式:紧耦合,不易扩展 class Shape: pass class Line(Shape): pass class Rectangle(Shape): pass class Circle(Shape): pass class RedLine(Line): pass class GreenLine(Line): pass class BlueLine(Line): pass # 桥模式 # 组合的方式:松耦合,易于扩展 from abc import ABCMeta, abstractmethod class Shape(metaclass=ABCMeta): # 抽象 def __init__(self,color): self.color = color @abstractmethod def draw(self): pass class Color(metaclass=ABCMeta): # 实现者 @abstractmethod def paint(self,shape): pass class Rectangle(Shape): # 细化抽象 name = "长方形" def draw(self): # 长方形的逻辑 self.color.paint(self) class Circle(Shape): # 细化抽象 name = "圆形" def draw(self): # 圆形的逻辑 self.color.paint(self) class Line(Shape): # 细化抽象 name = "直线" def draw(self): # 直线的逻辑 self.color.paint(self) class Red(Color): # 具体实现者 def paint(self,shape): print("红色的%s" % shape.name) class Green(Color): # 具体实现者 def paint(self,shape): print("绿色的%s" % shape.name) class Blue(Color): # 具体实现者 def paint(self,shape): print("蓝色的%s" % shape.name) # client # 因为Rectangle类继承了Shape类,而Shape类的构造方法需要color参数,所以要在实例化时传一个color的对象Red() shape = Rectangle(Red()) shape.draw() shape2 = Line(Blue()) shape2.draw()
应用场景:
当事物有两个维度上的表现,两个维度都可能扩展时。
优点:
内容:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
角色:
抽象组件(Component)
叶子组件(Leaf)
复合组件(Composite)
客户端(Client)
代码示例:
# 组合模式 from abc import ABCMeta, abstractmethod class Graphic(metaclass=ABCMeta): # 抽象组件 @abstractmethod def draw(self): pass class Point(Graphic): # 叶子组件 def __init__(self, x, y): self.x = x self.y = y def __str__(self): return "点(%s,%s)" % (self.x,self.y) def draw(self): print(str(self)) # 把自己通过__str__方法变成字符串再打印 class Line(Graphic): # 叶子组件 def __init__(self, p1, p2): self.p1 = p1 self.p2 = p2 def __str__(self): return "线段[%s,%s]" % (self.p1,self.p2) def draw(self): print(str(self)) class Picture(Graphic): # 复合组件 def __init__(self,iterable): self.children = [] for g in iterable: self.add(g) def add(self,graphic): self.children.append(graphic) def draw(self): print("------复合图形------") for g in self.children: g.draw() print("------复合图形------") # client客户端 p1 = Point(2,3) l1 = Line(Point(3,4),Point(6,7)) l2 = Line(Point(1,5),Point(2,8)) pic1 = Picture([p1,l1,l2]) p2 = Point(4,4) l3 = Line(Point(1,1),Point(0,0)) pic2 = Picture([p2,l3]) pic = Picture([pic1,pic2]) pic.draw()
内容:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
角色:
外观(facade)
子系统类(subsystem classes)
代码示例:
# 外观模式 class CPU: # 子系统类 def run(self): print("CPU开始运行") def stop(self): print("CPU停止运行") class Disk: # 子系统类 def run(self): print("硬盘开始工作") def stop(self): print("硬盘停止工作") class Memory: # 子系统类 def run(self): print("内存通电") def stop(self): print("内存通电") class Computer: # 外观 def __init__(self): self.cpu = CPU() self.disk = Disk() self.memory = Memory() def run(self): self.cpu.run() self.disk.run() self.memory.run() def stop(self): self.cpu.stop() self.disk.stop() self.memory.stop() # client computer = Computer() computer.run() computer.stop()
内容:为其他对象提供一种代理以控制对这个对象的访问。
应用场景:
远程代理:为远程的对象提供代理。
虚代理:根据需要创建很大的对象。例如浏览器的无图模式,就是一开始不加载图片,显示的是一个小方框(图片类的虚代理),有需要了点开才加载图片。
保护代理:控制对原始对象的访问,用于对象有不同访问权限时。
角色:
抽象实体(Subject)
实体(RealSubject)
代理(Proxy)
代码示例:
# 代理模式 from abc import ABCMeta, abstractmethod class Subject(metaclass=ABCMeta): # 抽象实体 @abstractmethod def get_content(self): pass @abstractmethod def set_content(self,content): pass class RealSubject(Subject): # 实体 def __init__(self,filename): self.filename = filename f = open(filename, 'r') print("读取文件内容") 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) f.close() # 虚代理: class VirtualProxy(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() def set_content(self,content): if not subj: self.subj = RealSubject(self.filename) return self.subj.set_content(content) # 保护代理: class ProtectedProxy(Subject): def __init__(self,filename): self.subj = RealSubject(filename) def get_content(self): return self.subj.get_content() def set_content(self,content): raise PermissionError("无写入权限") # client # subj = RealSubject("test.txt") # subj.get_content() # subj = VirtualProxy("test.txt") subj = ProtectedProxy("test.txt") print(subj.get_content()) subj.set_content('xxx')
略
略
内容:使多个对象都有机会处理请求,从而避免请求得发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
角色:
抽象处理者(Handler)
具体处理者(ConcreteHandler)
客户端(Client)
代码示例:
# 责任链模式 from abc import ABCMeta, abstractmethod class Handler(metaclass=ABCMeta): # 抽象处理者 @abstractmethod def handle_leave(self,day): pass class GeneralManager(Handler): # 具体处理者 def handle_leave(self,day): if day <= 10: print("总经理准假%d天" % day) else: print("你还是辞职吧") class DepartmentManager(Handler): # 具体处理者 def __init__(self): self.next = GeneralManager() def handle_leave(self,day): if day <= 5: print("部门经理准假%d天" % day) else: print("部门经理职权不足") self.next.handle_leave(day) class ProjectDirector(Handler): # 具体处理者 def __init__(self): self.next = DepartmentManager() def handle_leave(self,day): if day <= 1: print("项目主管准假%d天" % day) else: print("项目主管职权不足") self.next.handle_leave(day) # client day = 4 h = ProjectDirector() h.handle_leave(day)
适用场景:
有多个对象可以处理一个请求,哪个对象处理由运行时决定。
在不明确接收者的情况下,向多个对象中的一个提交一个请求。
优点:
降低耦合度:一个对象无需知道是其他哪一个对象处理其请求。
内容:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。观察者模式又称“发布-订阅”模式。
角色:
抽象主题(Subject)
具体主题(ConcreteSubject) ——发布者
抽象观察者(Observer)
具体观察者(ConcreteObserver) ——订阅者
代码示例:
# 观察者模式 from abc import ABCMeta, abstractmethod class Observer(metaclass=ABCMeta): # 抽象观察者(订阅者) @abstractmethod def update(self, notice): # 这里的notice参数是一个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 obs in self.observers: obs.update(self) class StaffNotice(Notice): def __init__(self,company_info=None): super().__init__() # 调用父类__init__函数声明observers属性 self.__company_info = 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() # 推送 # obj = StaffNotice() # print(obj.__company_info) # 在类外无法访问私有成员 # obj = StaffNotice("abc") # obj.company_info = "xyz" # 直接跳到@company_info.setter 执行下面的函数 # print(obj.company_info) class Staff(Observer): def __init__(self): self.company_info = None def update(self, notice): self.company_info = notice.company_info # client notice = StaffNotice("初始公司信息") s1 = Staff() s2 = Staff() notice.attach(s1) notice.attach(s2) notice.company_info = "公司今年业绩非常好,给大家发奖金!" # 手动修改company_info print(s1.company_info) print(s2.company_info) notice.detach(s2) notice.company_info = "公司明天放假" print(s1.company_info) print(s2.company_info)
内容:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
角色:
抽象策略(Strategy)
具体策略(ConcreteStrategy)
上下文(Context)
代码示例:
# 策略模式 from abc import ABCMeta, abstractmethod class Strategy(metaclass=ABCMeta): # 抽象策略 @abstractmethod def execute(self,data): pass class FastStrategy(Strategy): # 具体策略 def execute(self,data): print("用较快的策略处理%s" % data) class SlowStrategy(Strategy): # 具体策略 def execute(self,data): print("用较慢的策略处理%s" % data) class Context: # 上下文 def __init__(self, strategy, data): self.data = data self.strategy = strategy def set_strategy(self, strategy): # 设置策略 self.strategy = strategy def do_strategy(self): # 执行策略 self.strategy.execute(self.data) # client data = "[...]" s1 = FastStrategy() s2 = SlowStrategy() context = Context(s1,data) context.do_strategy() context.set_strategy(s2) context.do_strategy()
优点:
缺点:
客户端client必须了解不同的策略。
内容:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
角色:
抽象类(AbstractClass):定义抽象的原子操作(钩子操作),实现一个模板方法作为算法的骨架。
具体类(ConcreteClass):实现原子操作。
代码示例:
# 模板方法模式 from abc import ABCMeta, abstractmethod from time import sleep class Window(metaclass=ABCMeta): # 抽象类 @abstractmethod def start(self): pass @abstractmethod def repaint(self): pass @abstractmethod def stop(self): pass def run(self): # 模板方法 self.start() while True: try: self.repaint() sleep(1) except KeyboardInterrupt: # 发送一个程序中断的命令,把程序停掉 break self.stop() # client class MyWindow(Window): # 具体类 def __init__(self,msg): self.msg = msg def start(self): print("窗口开始运行") def stop(self): print("窗口结束运行") def repaint(self): print(self.msg) MyWindow("hello...").run()
================================================================
参考文献:
https://www.cnblogs.com/alex3714/articles/5760582.html
本篇涉及代码见week19
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。