适配器模式
- 内容:将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
- 两种实现方式:
- 类适配器:使用多继承
- 对象适配器:使用组合
from abc import ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta):
@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 = NewBankPay()
p.pay(100)
# 二
p = PaymentAdapter(ApplePay())
p.pay(200)
银联支付100元.
苹果支付200元.
- 角色
- 目标接口(Target)
- 待适配的类(Adaptee)
- 适配器(Adapter)
- 适用场景:
- 想使用一个已经存在的类,而它的接口不符合你的要求
- (对象适配器)想使用一些已经存在的子类,但不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
桥模式
- 内容:
- 将一个事物的两个维度分离,使其都可以独立的变化
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)
shape = Rectangle(Red())
shape.draw()
红色的长方形
- 角色:
- 抽象(Abstraction))
- 细化抽象(RefinedAbstraction)
- 多实现者(Implementor)
- 具体实现者(Concretelmplementor)
- 应用场景:
- 多当事物有两个维度上的表现,两个维度都可能扩展时。
- 优点:
- 多抽象和实现相分离
- 优秀的扩展能力
组合模式
- 内容:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
- 角色:
- 抽象组件(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):
print("------复合图形------")
for g in self.children:
g.draw()
print("----复合图形----")
p1 = Point(2, 3)
l1 = Line(Point(1, 1), Point(3, 4))
l2 = Line(Point(2, 1), Point(2, 5))
pic1 = Picture([p1, l1, l2])
pic1.draw()
print('*' * 30)
pic2 = Picture([pic1, Point(5, 5)])
pic2.draw()
------复合图形------
点(2, 3)
线段[点(1, 1), 点(3, 4)]
线段[点(2, 1), 点(2, 5)]
----复合图形----
******************************
------复合图形------
------复合图形------
点(2, 3)
线段[点(1, 1), 点(3, 4)]
线段[点(2, 1), 点(2, 5)]
----复合图形----
点(5, 5)
----复合图形----
- 适用场景:
- 表示对象的“部分-整体”层次结构(特别是结构是递归的》
- 希望用户忽略组合对象与单个对象的不同,用户统一地使用组合结构中的所有对象
- 优点
- 定义了包含基本对象和组合对象的类层次结构
- 简化客户端代码,即客户端可以一致地使用组合对象和单个对象
- 更容易增加新类型的组件
外观模式
- 内容:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
- 角色:
- 外观(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()
# 客户端
computer = Computer()
computer.run()
computer.stop()
CPU开始运行
硬盘开始运行
内存开始运行
CPU停止运行
硬盘停止运行
内存停止运行
优点:
- 减少系统相互依赖
- 提高了灵活性
- 提高了安全性
代理模式
- 内容:为其他对象提供一种代理以控制对这个对象的访问。
- 应用场景:
- 远程代理:为远程的对象提供代理
- 虚代理:根据需要创建很大的对象
- 保护代理:控制对原始对象的访问,用于对象有不同访问权限时
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(self.filename, "r", encoding="utf-8")
print("读取文件内容")
self.content = f.read()
f.close()
def get_content(self):
return self.content
def set_content(self, content):
f = open(self.filename, "w", encoding="utf-8")
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("无写入权限")
# subj = RealSubject("test.txt") # 即使不调用get_content方法,也会读取文件内容
# subj = VirtualProxy("test.txt") # 不调用get_content方法,不会读取文件内容
# print(subj.get_content())
subj = ProtectedProxy("test.txt") # 可以get_content,但不能set_content
print(subj.get_content())
subj.set_content("123")
读取文件内容
文件内容示例
---------------------------------------------------------------------------
PermissionError Traceback (most recent call last)
Cell In[10], line 68
66 subj = ProtectedProxy("test.txt") # 可以get_content,但不能set_content
67 print(subj.get_content())
---> 68 subj.set_content("123")
Cell In[10], line 55, in ProtectedProxy.set_content(self, content)
54 def set_content(self, content):
---> 55 raise PermissionError("无写入权限")
PermissionError: 无写入权限
- 角色:
- 抽象实体(Subject)
- 实体(RealSubject)
- 代理(Proxy)
- 优点
- 远程代理:可以隐藏对象位于远程地址空间的事实
- 虚代理:可以进行优化,例如根据要求创建对象
- 保护代理:允许在访问一个对象时有一些附加的内务处理