1. 设计模式
对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。每一个设计模式系统的命名、解释和评价了面向对象系统中一个总要的和重复出现的设计。
2. 接口
若干抽象方法的集合
作用:限制实现接口的类必须实现接口给定的调用方式实现这些方法;对高层模块隐藏了类的内部实现。
例:
# 方式一:raise NotImplementedError, 必须重写方法,但如果不调用该方法,则不会报错
class Payment(object):
def pay(self, money):
raise NotImplementedError
class Alipay(Payment):
def pay(self, money):
pass
# 方式二:抽象类,必须重写方法,且必须实现具体的代码
from abc imort ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
class WechatPay(Payment):
def pay(self, money):
3. 面向对象设计SOLID原则
- 开放封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
- 里氏替换原则:所有引用父类的地方必须能透明地使用其子类的对象。
- 依赖倒置原则:高层模型不应该依赖底层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程。
- 接口隔离原则:使用多个专门的接口,而不是用单一的总接口,即客户端不应该依赖那些它不需要的接口。
- 单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
4. 设计模式分类
创建型模式(5种):工厂方法模式、抽象工厂模式、创建者模式、原型模式、单例模式
结构型模式(7种):适配器模式、桥模式、组合模式、装饰模式、外观模式、享元模式、代理模式
行为型模式(11种):解释器模式、责任链模式、命令模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、访问者模式、模板方法模式
5. 简单工厂模式
不直接向客户端爆率对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。
1)角色:
工厂角色(Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
2)案例:
from abc imort ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self, money):
pass
class WechatPay(Payment):
def pay(self, money):
print("微信支付")
class AliPay(Payment):
def pay(self, money):
print("支付宝支付")
class PaymentFactory:
def create_payment(self, method):
if method == "alipay":
return AliPay()
elif method == "wechat":
return WechatPay()
else:
raise TypeError("无此支付方式" % method)
3)优点:
- 隐藏了对象创建的实现细节
- 客户端不需要修改代码
4)缺点:
- 违反了单一职责原则,将创建逻辑集中到一个工厂类里
- 当添加新产品时,需要修改工厂类代码,违法呢开闭原则
6. 工厂方法模式
定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类
1)角色:
抽象工厂角色(Creator)
具体工厂角色(Concrete Creator)
抽象产品角色(Product)
具体产品角色(Concreate Product)
例:
class PaymentFactory(metaclass=ABCMeta):
@abstractmethod
def create_payment(self):
pass
class AliPayFactory(PaymentFactory):
def create_payment(self):
return AliPay()
def WechatPayFactory(PaymentFactory):
def create_payment(self):
return WechatPay()
2)优点:
- 每个具体产品都对应一个具体工厂类,不需要修改工厂类代码
- 隐藏了对象创建的实现细节
3)缺点:
- 每增加一个具体产品类,就必须增加一个相应的具体工厂类
7. 抽象工厂模式
定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象。
相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一套产品。
1)角色
- 抽象工厂角色(Creator)
- 具体工厂角色(Concreate 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 SnapDragon(CPU):
def show_cpu(self):
print(...")
class Andriod(OS):
def show_os(self):
print("...")
class MiFactory(PhoneFactory):
def make_cpu(self):
return SnapDragonCPU()
def make_os(self):
return Andriod()
def make_shell(self):
return SmallShell()
2)优点:
将客户端与类的具体实现相分离
每个工厂创建了一个完整的产品系列,使得易于交换产品系列
有利于产品的一致性(即产品之间的约束关系)
3)缺点:
难以支持新种类的(抽象)产品
8. 建造者模式
将一个复杂对象的创建与它的表示分离,使得同样的创建过程可以创建不同的表示。
1)角色:
- 抽象建造者(Builder)
- 具体建造者(Concrete Builder)
- 指挥着(Director)
- 产品(Product)
例:
from abc import ABCMeta, abstractmethod
class Player:
def __init__(self, face, body, arm, leg):
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
@abstrctmethod
def build_arm(self):
pass
@abstractmethod
def build_leg(self):
pass
class HuamnWarriorBuilder(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 = "战士腿“
建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象
2)优点:
隐藏了一个产品的内部构造和装配过程
将构造代码与表示代码分开
可以对构造过程进行更精细的控制
3)缺点:
9. 单例模式
保证一个类只有一个实例,并提供一个访问它的全局访问点。
1)角色:
单例(singleton)
2)优点:
对唯一实例的受控访问
单例相当于全局变量,但防止了命名空间被污染
例:
class Singleton:
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, a):
self.a = a
a = MyClass(10)
b = MyClass(11)
print(id(a), id(b))
10. 适配器模式
将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
两种实现方式:
- 类适配器:使用多继承
- 对象适配器:使用组合
例:
from abc import ABCMeta, abstractmethod
class Payment(object):
@abstractmethod
def pay(self, money):
pass
class BankPay:
def cost(self, money):
print("银行卡支付%s" % 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(ApplyPay())
p.pay(100)
1)角色
- 目标接口(Target)
- 带适配的类(Adaptee)
- 适配器(Adapter)
2)适用场景:
- 想使用一个已经存在的类,而它的接口不符合要求
- 想使用一些已经存在的子类,但不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
11. 桥模式
将一个事物的两个维度分离,使其都可以独立地变化。
例:
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 Red(Color):
def paint(self, shape):
print("红色的%s" % shape.name)
class Green(Color):
def paint(self, shape):
print("绿色的%s" % shape.name)
1)角色:
- 抽象(Abstraction)
- 细化抽象(RefinedAbstraction)
- 实现者(Implementor)
- 具体实现者(ConcreteImplementor)
2)应用场景:
当事物有两个维度上的表现,两个维度都可能扩展时。
3)优点:
- 抽象和实现相分离
- 优秀的扩展能力
12. 组合模式
将对象组合成树形结构以表示”部分-整体“的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
1)角色:
- 抽象组件(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))
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):
for g in self.children:
g.draw()
2)适用场景:
- 表示对象的”部分-整体“层次结构(特别是结构是递归的)
- 希望用户忽略组合对象与单个对象的不同,用户统一地使用组合结构中的所有对象
3)优点:
- 定义了包含基本对象和组合对象的类层次结构
- 简化客户端代码,即客户端可以一致的使用组合对象和单个对象
- 更容易增加新类型的组件
13. 外观模式
为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
1)角色:
外观(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.cpu.stop()
self.memory.stop()
2)优点:
- 减少系统相互依赖
- 提供了灵活性
- 提高了安全性
14. 代理模式
为其他对象提供一种代理以控制对这个对象的访问
1)应用场景:
远程代理:为远程的对象提供代理
虚代理:根据需要创建很大的对象
保护代理:控制对原始对象的访问,用于对象有不同访问权限时
例:
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)
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 self.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("无写入权限")
2)角色:
- 抽象实体(Subject)
- 实体(RealSubject)
- 代理(Proxy)
3)优点:
远程代理:可以隐藏对象位于远程地址空间的事实
虚代理:可以进行优化,例如根据要求创建对象
保护代理:允许在访问一个对象时有一些附加的内务处理
15. 责任链模式
使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
1)角色:
- 抽象处理者(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("总经理准假%s天" % day)
else:
print("辞职吧")
class DepartmentManager(Handler):
def __init__(self):
self.next = GeneralManager()
def handle_leave(self, day):
if day <= 5:
print("部门经理准假%s天" % day)
else:
print("部门经理权限不足")
self.next.handle_leave()
class ProjectDirector(Handler):
def __init__(self):
self.next = DepartmentManager()
def handle_leave(self, day):
if day <= 3:
print("项目主管准假%s天" % day)
else:
print("项目主管权限不足")
self.next.handle_leave()
2)适用场景:
- 有多个对象可以处理一个请求,哪个对象处理由运行时决定
- 在不明确接收者的情况下,向多个对象中的一个提交一个请求
3)优点:
降低耦合度:一个对象无需知道是其他哪一个对象处理器请求
16. 观察者模式
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。观察者模式又称”发布-订阅“模式
1)角色:
- 抽象主题(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)
def notify(self):
for obs in self.observers:
obj.update(self)
class StaffNotice(Notice):
def __init__(self, company_info):
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 Staff(Observer):
def __init__(self):
self.company_info = None
def update(self, notice):
self.company_info = notice.company_info
2)适用场景:
- 当一个抽象模型有两方面,其中一个方面依赖于另一个方面。将这两者封装在独立对象中以使它们可以各自独立的改变和复用。
- 当对一个对象的改变需要改变其他对象,而不知道具体有多少对象有待改变。
- 当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之,你不希望这些对象是紧密耦合的。
优点:
- 目标和观察者之间的抽象耦合最小
- 支持广播通信
17. 策略模式
定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
1)角色:
- 抽象策略(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)
2)优点:
- 定义了一系列可重用的算法和行为
- 消除了一些条件语句
- 可以提供相同行为的不同实现
3)缺点:
- 客户必须了解不同的策略
18. 模板方法模式
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
1)角色:
抽象类(AbstractClass):定义抽象的原子操作(钩子操作);实现一个模板方法作为算法的骨架。
具体类(ConcreteClass):实现原子操作
例:
from abc import ABCMeta, abstractmethod
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()
except KeyboardInterrupt:
break
self.stop()
class MyWindow(Window):
def __init__(self, msg):
self.msg = msg
def start(self):
print("窗口开始运行")
def stop(self):
print("窗口停止运行")
def repaint(self):
print(self.msg)
2)适用场景:
- 一次性实现一个算法的不变的部分
- 各个子类中的公共行为应该不被提取出来并集中到一个公共父类中以避免代码重复
- 控制子类扩展