Python之设计模式学习
python是面向对象的动态编程语言。
面向对象的三大特性:封装、继承、多态
1、接口:抽象方法的集合
from abc import ABCMeta, abstractmethod
# 定义抽象接口
class Payment(met=ABCMeta):
@abstractmethod
def pay(self, money):
pass
2、设计原则:
开放封闭原则,
里氏替换原则
依赖倒置原则
接口隔离原则
单一责任原则
3、设计模式分类:
创建型模式:5(用户主要以借口为准,不需要了解内部实现)
工厂方法模式、抽象工厂模式、创建者模式、原型模式、单例模式
结构型模式:7
适配器模式、桥模式、组合模式、装饰模式、外观模式、享元模式、代理模式
行为型模式:11
解释器模式、责任链模式、命令模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、访问者模式、模板方法模式
创建型模式
工厂方法模式
通过定义工厂的抽象接口,使得接口隔离、责任单一。
对象包括抽象工厂、具体工厂、抽象产品、具体产品。
优缺点:
实现具体工厂不需要修改代码、实现隐藏对象的细节。
没个具体产品对应一个工厂,代码多。
class Payment(met=ABCMeta):
@abstractmethod
def pay(self, money):
pass
抽象工厂模式
通过定义抽象接口,中包括多个对象生成一套。需限制产品配套使用,设计具体工厂。
优缺点:
参照接口,具体工厂直接封装,利于产品一致性,改变具体工厂中单个属性较容易。
工厂增加新的属性困难。
创建者模式
在抽象工厂基础上,进一步封装一个Director进行指挥代码调用顺序。
优缺点:
构造代码与标识代码分离,能对结构中流程控制更加灵活,隐藏内部实现。
单例模式
应用于确保唯一的数据,
通过定义new魔术方法,确保一个类只返回一个实例,物理地址唯一。
优点:
对唯一实例的受控访问,相当于全局变量,但命名空间未被污染。
# 单例模式
class singlee:
def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
cls._instance = super(singlee, cls).__new__(cls)
return cls._instance
class Myclass(singlee):
def __init__(self, a):
self.a = a
a = Myclass(10)
# 被b调用覆盖前
print(a, id(a))
print(a.a)
b = Myclass(20)
# 被b调用覆盖前
print(a, id(a))
print(a.a)
print(b, id(b))
print(b.a)
<__main__.Myclass object at 0x7f47d147a240> 139946430538304
10
<__main__.Myclass object at 0x7f47d147a240> 139946430538304
20
<__main__.Myclass object at 0x7f47d147a240> 139946430538304
20
结构型模式 :
适配器模式
通过增加中间转换,将一方方法通过另一种的方法的封装进行调用
(目标接口、待适配的类、适配器)
解决存在于两个系统合并,代码定义属性名称不一致,无法调用等问题
# 类适配器模式——少数对象不一致
class NewPay(转换为对象, 装换的对象):
def 转换为对象de属性名称(self, 参数):
self.装换的对象de属性名称(参数)
# 对象适配器——多个对象
class NewPay(转换为对象):
def __init__(self, 转换为对象):
self.转换为对象 = 转换为对象
# 对对象进行封装再通过类方法调用
def 转换为对象de属性名称(self, 参数):
self.装换的对象de属性名称(参数)
p = NewPay(装换的类对象)
# 调用方法进行转换
P.转换为对象de属性名称(参数)
桥模式
数据联系方式——继承、组合
继承,紧耦合不方便扩展
组合,松耦合方便不同维度扩展
(包括抽象、细化抽象、实现者、具体实现者)
事物有两个维度上扩展的需求时使用。
优缺点:
抽象和实现相分离,采用组合方式高扩展性。
from abc import ABCMeta, abstractmethod
class Hang(metaclass=ABCMeta):
# 通过定义成属性,将Lie类与Hang类组合
def __init__(self, lie):
self.lie = lie
@abstractmethod
def hanghao(self):
pass
class Lie(metaclass=ABCMeta):
@abstractmethod
def liehao(self, hang):
pass
class hang3(Hang):
v = "第三行"
def hanghao(self):
self.lie.liehao(self)
class hang4(Hang):
v = '第四行'
def hanghao(self):
self.lie.liehao(self)
class lie2(Lie):
def liehao(self, hang):
print("%s这是第二列" % hang.v)
class lie3(Lie):
def liehao(self, hang):
print("%s这是第三列" % hang.v)
hangss = hang3(lie2())
hangss.hanghao()
第三行这是第二列
组合模式
表现部分与整体的层次结构,特别是有递归需求。希望组合对象与单个对象均采用统一抽象接口,适用于结构中所有对象。
(抽象组件、叶子组件、复合组件、#客户端)
优缺点:更容易增加新功能组件(可扩展性),结构层次——树状,统一抽象接口。
from abc import ABCMeta, abstractmethod
class Abstac(metaclass=ABCMeta):
@abstractmethod
def draw(self):
pass
# 叶子组件
class Poin(Abstac):
def __init__(self, poin):
self.poin = poin
def __str__(self):
return "%s点" % self.poin
def draw(self):
print(str(self))
# 叶子组件
class Lin(Abstac):
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))
# 简单组合模型
# a = Lin(Poin(2), Poin(10))
# print(a)
# 复合组件
class Comp(Abstac):
def __init__(self, iterable):
# 创建child列表接收数据
self.child = []
for c in iterable:
# 调用方法追加入child
self.adds(c)
def adds(self, grapsh):
self.child.append(grapsh)
# 递归函数
def draw(self):
print("----复合图形----")
# 从child列表中循环调用draw方法
for g in self.child:
g.draw()
print("----复合图形----")
#复合组成(树状结构)
b = Poin(12)
a = Lin(Poin(2), Poin(10))
c = Lin(Poin(44), Poin(9))
com = Comp([b, a, c])
com.draw()
外观模式
将功能进一步整合封装,调用封装的类产生不同的模式。
(外观、子系统类)
优缺点:
减少系统底层和高层依赖(都依赖于实例化的接口),降低复杂系统调用错误率,更高程度封装不显示底层细节,侧重于接口提供的功能模式。
代理模式
为其他对象控制此对象设置的中介
(抽象实体、实体、代理)
三大代理模式:
1、远程代理;访问远端或其他数据做出转接
2、虚代理;对现有对象功能进行继承重写(扩展)
3、保护代理;(控制访问权限)
优缺点:
远程:隐藏对象远程地址空间
虚代理:优化功能,创建对象
保护代理:访问对象附加业务处理
# 代理模式
from abc import ABCMeta, abstractmethod
class Age(metaclass=ABCMeta):
@abstractmethod
def open_fi(self):
pass
@abstractmethod
def close_fi(self, content):
pass
# 文件写入——远端代理
class Realsub(Age):
def __init__(self, filename):
self.filename = filename
f = open(self.filename, 'r', encoding='utf-8')
self.content = f.read()
f.close()
def open_fi(self):
return self.content
def close_fi(self, content):
f = open(self.filename, 'w', encoding='utf-8')
f.write(content)
f.close()
# 虚代理(调用时判断状态,文件写入方法调用时才打开,节省内存空间)
class VirturlPro(Age):
def __init__(self, filename):
self.filename = filename
self.subj = None
def open_fi(self):
if not self.subj:
#增加判断,使得open_fi只有在调用时才会启动。
self.subj = Realsub(self.filename)
return self.subj.open_fi()
def close_fi(self, content):
pass
# 保护代理(设置访问权限)
class ProtectPor(Age):
def __init__(self, filename):
self.subj = Realsub(filename)
def open_fi(self):
return self.subj.open_fi()
def close_fi(self, content):
raise PermissionError("无写入权限")
# sub = Realsub('books.txt')
# sub.open_fi()
# sub1 = VirturlPro('books.txt')
# sub1.open_fi()
# sub = ProtectPor('books.txt')
# sub.close_fi("abc")
行为型模式
责任链模式
传入请求可能需要多个对象处理,为避免请求处理的耦合关系。将对象串联或并联成链,进行判断处理。(一对多)
(抽象处理者、具体处理者、#用户端)
优缺点:
降低耦合度,无需知道谁处理,只需从链头传入进行判断。
案例:python中的scrapy的pipeling
观察者模式(发布-订阅模式)
一对多的发布—订阅依赖关系。——松耦合
用于封装多对多,往往一方依赖于另一方,但两则需要独立封装(不希望紧密耦合)。发布者改变后订阅者自动改变,不需要知道有哪些需要手动改变。
(抽象主题、具体主题、抽象观察者、具体观察者)
优缺点:
抽象耦合性小,支持广播通信。
from abc import ABCMeta, abstractmethod
# 抽象订阅者
class Users(metaclass=ABCMeta):
@abstractmethod
def update(self, notice):
pass
# 抽象发布者
class Cortlcent:
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 Duyueming(Cortlcent):
def __init__(self, centel_info):
super().__init__()
# 创建为私有属性
self.__centel_info = centel_info
# 属性装饰器语法
@property
def centel_info(self):
return self.__centel_info
# 负责重写方法
@centel_info.setter
def centel_info(self, info):
self.__centel_info = info # 实现自己更新
self.notify() # 推送
class Used(Users):
def __init__(self):
self.centel_info = None
def update(self, notice):
self.centel_info = notice.centel_info
notice = Duyueming("公司信息")
# 订阅者
s1 = Used()
s2 = Used()
# 绑定订阅者
notice.attach(s1)
notice.attach(s2)
# 发布信息
notice.centel_info = "信息已发布"
print(s1.centel_info)
# 取消订阅
notice.detach(s2)
notice.centel_info = "无信息发布"
print(s1.centel_info)
print(s2.centel_info)
策略模式
定义算法后分别封装,且相互可替换。使根据条件切换不同算法。
(抽象策略、具体策略、上下文)
优缺点:
可重用算法和行为,消除一些条件语句,可提供相同行为不同实现方式(封装可替换)。
使用者必须清楚不同策略的使用场景
模板方法模式
定义抽象接口中存在部分算法核心代码已经实现细节,其他方法框架搭建需要开发。
各子类公共部分代码提取到公共父类(代码复用),控制子类扩展,实现核心代码不变
(抽象类【原子操作、钩子操作】、具体类【实现原子操作】)
优缺点:
代码复用,框架搭建更快
模板代码公用导致个别方法无法实现。