1.设计模式
设计模式中使用了一个接口类
abc:Abstract Base Classes
作用:在代码中定义和使用抽象基类进行API检查。
为什么使用abc模块
Abstract base classes由一组接口组成,检查比hasattr()更严格。通过定义一个抽象基类,可以为一组子类定义一个通用的API。这对于第三方为应用提供插件等非常有用,另外当您在一个大型的团队中工作或在一个大型的代码库中,同时将所有的类放在您的头脑中是困难或不可能的时,它也可以帮助您。
abc模块的工作机制:
1.利用abc模块设置一个抽象类,并且设置一个类继承这个类,而设置的类必须按照抽象类的方法定制方法
例如定义一个抽象类
impout abc # 导入abc类
# 使用abc类创建一个抽象的类
class A(abc.ABCMeta):
@abc.abstractmethod
def load(self,input):
pass
# 创建一个子类,继承抽象类,继承后必须按照抽象类的方法的形式进行编写(参数和名字,内部的逻辑自行编写)
class B(A):
def load(self,input):
pass
对软件设计中普遍存在的各种问题,所提出来的方案,每一个设计模式的命名,解释评价面向对象系统中一个重要的和重复的设计
面向对象的三大特征:
封装 继承 多态
接口是什么:若干抽象方法的集合
作用:限制现实的接口的类必须按照给定的调用方法实现这些方法,对高层模块隐藏了类的内部实现
设计模式:是一种反复被使用,经过分类编目,代码设计经验的总结,使用设计模式可以重用代码,让代码更容易被人理解,保证代码的可靠性,程序的重用性
设计模式遵守
1.开方原则:
一个软件实体如类,模块和函数应该对扩展开放,对修改进行关闭,软件应在不修改原有代码的情况下进行扩展
尽量不要改代码
2.里氏替换原则:
所有引用父类的地方必须透明的使用子类的对象
传入 usre 不会报错
传入 vipusre 不会报错
class User:
def show_name(self):
pass
class VIPUser(User):
def show_name(self):
pass
# 保证两个返回值,参数都是一样的,内部逻辑可以不同
3.依赖倒置原则:
高层模块不应该依赖底层模块,都要依赖抽象,抽象不应该依赖细节,细节一栏抽象,
针对接口进行变成,而不是针对实现编程
先定义接口,按照接口进行编程
4.接口隔离原则
使用多个专门的接口,而不使用单一的总接口,客户端不应该依赖哪些它不需要的接口
在创建接口时,不能直接创建一个大的接口类,而是按照功能需求取创建
不需要依赖哪些不需要使用的接口,将接口进行细化,那个类需要,那个类继承
例如:
创建一个陆地动物类接口
创建一个飞禽动物类接口
创建一个水螅动物类接口
青蛙:可以继承落地动物类接口和水螅动物类接口
老虎:只能继承陆地动物类接口
老鹰:只能继承飞禽动物类接口
4.单一职责原则:不要存在多余一个导致类变更的原因,通俗的说,一个类只能负责一项职责
面向对象和设计模式:都要依赖solid原则
2.设计模式分类
创建型模式
创建型模式概念:
处理对象创建的设计模式,试图根据实际情况使用合适的方式创建对象。基本的对象创建方式可能会导致设计上的问题,或增加设计的复杂度。创建型模式通过以某种方式控制对象的创建来解决问题
创建型模式由两个主导思想构成:
一是将系统使用的具体类封装起来,二是隐藏这些具体类的实例创建和结合的方式
简单工厂模式(先使用)
在创建对象时使用的模式
1.简单工厂模式
内容:不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责类的实例
工厂角色:工厂类
抽象产品:接口类
具体产品:就是根据接口集体实现的功能
优点:
隐藏对像创建的实现细节
客户端不需要修改代码
缺点:
违反单一职责原则,将创建的逻辑都放入工厂类中
添加新产品时需要修改工厂类代码,违反开闭原则
代码案例:
import abc # 抽象基类方法
# 属于一个接口类,或者抽象类,使用这个类为父类的子类,必须使用接口类中的方法和参数
class Payment(metaclass=abc.ABCMeta):
@abc.abstractmethod
def pay(self, money):
pass
# 继承抽象类
class Alipay(Payment): # 支付宝类
def __init__(self, use_huabai=False):
# 定义一个花呗的支付方式
self.use_huabai = use_huabai
def pay(self, money):
if self.use_huabai:
print("花呗支付{}元".format(money))
else:
print("支付宝支付{}元".format(money))
# 继承抽象类
class Weixinpay(Payment): # 抽象类
def pay(self, money):
print("微信支付{}元".format(money))
# 工厂类:主要负责处理实现功能的类的逻辑
class Factory:
def factory_pay(self, types):
if types == 'alipay':
return Alipay()
elif types == 'weixinpay':
return Weixinpay()
elif types == 'huabai':
return Alipay(use_huabai=True)
else:
raise Exception('输入有误')
f = Factory() # 实例化工厂类
a = f.factory_pay('huabai')
a.pay(100)
'''
当进行继承创建的抽象基类时,
继承的子类必须按照抽象基类中的方法进行创建,参数方法名要一直,内部的逻辑根据情况而定
使用工厂设置模式,逻辑判断上面使用的就是工厂类暴露出来的接口方法,而内部的高层代码(真正的逻辑没有暴露)
'''
工厂方法模式(先使用)
# 就是将工厂模式的类中设置一个接口,将内部的全部代码拆分
概念:定义一个工厂的接口类,让子类决定实例化那个产品
角色:
抽象工厂角色
具体工厂角色
抽象产品角色
具体产品角色
工厂也有接口,产品也有接口
优点:
每个具体产品都对应一个具体的工厂类,不需要修改工厂代码
隐藏了对象创建的实现细节
缺点:
没具体增加一个产品角色,就要增加一个工厂角色,代码比较多
实例代码:
import abc
# 属于一个接口类,或者抽象类,使用这个类为父类的子类,必须使用接口类中的方法和参数
class Payment(metaclass=abc.ABCMeta):
@abc.abstractmethod
def pay(self, money):
pass
# 继承抽象类
class Alipay(Payment): # 支付宝类
def __init__(self, use_huabai=False):
# 定义一个花呗的支付方式
self.use_huabai = use_huabai
def pay(self, money):
if self.use_huabai:
print("花呗支付{}元".format(money))
else:
print("支付宝支付{}元".format(money))
# 继承抽象类
class Weixinpay(Payment): # 微信支付类
def pay(self, money):
print("微信支付{}元".format(money))
# 创建一个工厂抽象类 接口
class Factory(metaclass=abc.ABCMeta):
@abc.abstractmethod
def to_pay(self):
pass
# 创建一个工厂角色
# 支付宝支付 角色
class Alipay_Factory(Factory):
def to_pay(self):
return Alipay()
# 支付宝花呗支付工厂角色
class Alipay_Huabai_Factory(Factory):
def to_pay(self):
return Alipay(use_huabai=True)
# 微信支付 角色
class Weixinpay_Factory(Factory):
def to_pay(self):
return Weixinpay()
w = Weixinpay_Factory()
f = w.to_pay()
f.pay(100)
'''
为工厂创建一个抽象类接口,然后对创建产品角色,创建一个工厂角色
不会产生代码都存在一个工厂中,出现代码过多,当新创建产品角色时,只需要创建一个工厂角色就可以
'''
抽象工厂模式(场景复杂,后使用)
概念:定义一个工厂类接口,让工厂子类创建一系列相关或者相互依赖的对象
给一套东西作为一个限制,进行限制方法。不是生成一个对象,而是生成一套对象,可以对对象加入限制
相对于工厂模式方法,抽象工厂模式中的每一个具体的工厂都生成一套产品
例如:
生产一个手机:需要手机壳,cpu,操作系统,每一个类对象都不同的种类,对每个具体工厂,分贝生成一部手机
所需要的三个对象
使用:太过复杂,局限性较大
角色:
抽象工厂角色
具体工厂角色
抽象产品角色
具体产品角色
客户端
优点:
将客户端与类的具体实现相分类的
每一个工厂创建一个具体的产品类型,十的易于交换产品系列
有利于产品的一致性
缺点:
难以支持新种类
代码案例:
import abc
# 产品抽象类
# 手机cpu
class Product_CPU(metaclass=abc.ABCMeta):
@abc.abstractmethod
def cpu(self):
pass
# 手机操作系统
class Product_OS(metaclass=abc.ABCMeta):
@abc.abstractmethod
def os(self):
pass
# 手机壳
class Product_Shell(metaclass=abc.ABCMeta):
@abc.abstractmethod
def shell(self):
pass
# 工厂抽象类 负责将手机窜在一起
class Factory(metaclass=abc.ABCMeta):
@abc.abstractmethod
def factory_cpu(self):
pass
@abc.abstractmethod
def factory_os(self):
pass
@abc.abstractmethod
def factory_shell(self):
pass
# 创建产品角色 cpu 晓龙/联发科/m1
class A_CPU(Product_CPU):
def cpu(self):
print("晓龙cpu")
class B_CPU(Product_CPU):
def cpu(self):
print("联发科cpu")
class C_CPU(Product_CPU):
def cpu(self):
print("m1cpu")
# 创建产品角色 系统 安卓/os
class A_OS(Product_OS):
def os(self):
print("安卓系统")
class B_OS(Product_OS):
def os(self):
print("os系统")
# 创建手机壳/ 大小
class Big_Shell(Product_Shell):
def shell(self):
print("大手机壳")
class Small_Shell(Product_Shell):
def shell(self):
print("小手机壳")
# 创建工厂角色
# 创建苹果手机
class Apple(Factory):
def factory_cpu(self):
return C_CPU()
def factory_os(self):
return B_OS()
def factory_shell(self):
return Small_Shell()
# 创建小米手机
class Millet(Factory):
def factory_cpu(self):
return B_CPU()
def factory_os(self):
return A_OS()
def factory_shell(self):
return Small_Shell()
# 创建客户端
class Client:
def __init__(self, cpu, os, shell):
# 传过来的是工厂角色的对象
self.cpu = cpu # 接受的就是 Millet().factory_xxx()中return返回的类对象B_OS()....
self.os = os
self.shell = shell
def phone(self):
# 调用产品中的方法
print('手机组成部分')
self.cpu.cpu() # 在根据返回的类对象,调用他内部的方法cpu打印对应的内容
self.os.os()
self.shell.shell()
def make_phon(factory):
# factory 工厂对象
cpu = factory.factory_cpu() # 类名调用对应的方法,的返回的类对象就是B_OS()....
os = factory.factory_os()
shell = factory.factory_shell()
return Client(cpu,os,shell) # Millet().factory_cpu()的实例对象,传入到客户端中
p = make_phon(Millet()) # 将手机组成的工厂类当对象传入make_phon方法中
p.phone()
'''
抽象工厂方法,使用的太过复杂
make_phon函数接受了一个角色工厂的类名(),根据类名调用类内部的3个方法:
1.factory_cpu()
2.factory_os()
3.factory_shell()
而这三个方法同时返回对应的产品角色的类对象
1.A_OS()
2.A_shell()
3.A_cpu()
在make_phon函数中有同时调用了客户端类,将这三个产品角色传入到客户端类的init方法中
获取了一个客户端类的实例化对象p
p同时调用了客户端类中的phone方法
而phone方法中:
调用了角色工厂中的方法进行打印信息
'''
建造者模式(场景复杂,后使用)
概念:将一个浮在对选哪个的构建与它的表示分离,使同样的构建过程可以创建不同的表示
# 与抽象工厂模式有点像
# 控制组装顺序
角色:
抽象创造者:接口
具体创造者:实现的抽象建造者的子类
指挥者
产品
重点:
它与抽象工厂相似,也用来创建复杂的对象,主要区别是建造者模式是一步步构造成为一个浮在的对象,而抽象工厂模式重于多个系列产品对象
优点:隐藏一个产品的内部结构和装配过程(用户不需要知道装配过程)
将构造的代码与表示代码分开
可以对构造过程有更细化的控制
代码:
import abc
# 导演类
class Player:
def __init__(self, face=None, body=None, arm=None, leg=None):
'''
人物建模类
:param face:头
:param body: 身体
:param arm: 胳膊
:param leg: 腿
'''
self.face = face
self.body = body
self.arm = arm
self.leg = leg
# __str__自动返回实例变量的全部的内容
def __str__(self):
return "{},{},{},{}".format(self.face, self.body, self.arm, self.leg)
# 创建构造工厂/创建抽象创造者
class PlayerBuilder(metaclass=abc.ABCMeta):
@abc.abstractmethod
def build_face(self):
pass
@abc.abstractmethod
def build_body(self):
pass
@abc.abstractmethod
def build_arm(self):
pass
@abc.abstractmethod
def build_leg(self):
pass
# 创建具体工厂角色/创建具体的创造者
class SexyGirlBuilder(PlayerBuilder):
def __init__(self, player):
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 duild_palyer(self, builder):
builder.build_body()
builder.build_face()
builder.build_arm()
builder.build_leg()
return builder.player # 将创建的建模类对象进行返回
# 实例化创建者对象,将建模类传入,因为创造者类中对建模类中的一些实例变量进行了赋值
s = SexyGirlBuilder(Player)
# 实例化控制着,这个类主要的作用就是控制创造者的组装顺序
d = PlayerDirector()
# 根据组长类中的方法进行传入,将创造者类的实例化对象传入,执行创造者类中的方法,进行赋值
m = d.duild_palyer(s) # 返回建模类的实例对象,建模类中__str__方法就会自动执行
print(m) #
'''
创造者模式分为4个部分
1.导演类:
导演类起到封装的作用,避免高层模块深入到建造者内部的实现类。在建造者模式比较庞大时,导演类可以有多个。
2.抽象的创造者
主要作用:负责将需要创建的方法进行声明
3.具体实现的创造者
主要作用:实现抽象创造者类中的全部方法
4.客户端/控制类
指挥具体实现创造者对象创建 产品
'''
单例模式1
单例模式:
保证一个类只有一个实例,并提供一个访问他的全局访问点
角色:单利
优点:
对唯一实例的受控访问
单例相当于一个全局变量,防止命名空间的污染
python的模块就是一个单例模式
单利模式的书写:
class Singleton:
instance = None
# 用来分配空间,是给整个类初始化
def __new__(cls, *args, **kwargs):
if cls.instance: # 判断是不是None
return cls.instance # 不是None就将原对象返回
else:
cls.instance = object.__new__(cls) # 如果是None,就创建一个空对象
return cls.instance #在将空对象返回
单例模式的求证案例:
class Singleton:
instance = None
# 用来分配空间,是给整个类初始化
def __new__(cls, *args, **kwargs):
if cls.instance: # 判断是不是None
return cls.instance # 不是None就将原对象返回
else:
cls.instance = object.__new__(cls) # 如果是None,就创建一个空对象
return cls.instance # 在将空对象返回
class A(Singleton):
def __init__(self, a):
self.a = a
a = A(10)
b = A(20)
print(a.a)
print(b.a)
'''
执行流程:
单例模式,当对A类进行实例化对象时,就会判断instance存不存在
如果instance不存在,就会执行else中的代码:
cls.instance = object.__new__(cls),创建一个对象,将只返回
当创建第二个实例对象b时,就会进行判断 if cls.instance,存在值还将原值进行返回。
单例模式就是一直使用的是一个,实例化对象。确保一个类只有一个实例对象
Python new()方法,为对象分配内存,返回对象的引用
利用id()方法判断是不是用的一个实例化对象
'''
应用场景:日志对象,数据库链接器,文件系统,只有一个实例存在就用单利模式
单例模式2
单例模式:就是当对类进行实例化是,可以使用一个内存地址
正常情况:每一次实例化,对象的内存地址都不一样。
单例模式的方式:
import threading #导入线程模块
class 类名(object):
lock = threading.RLock() # 创建一把锁
instance = None # 设置类变量
def __new__(cls,*args,**kwargs):
# 在实例化对象之前先执行new方法 创建一个空对象
# 返回一个空对象
# 直接读取,而不会 申请锁 在进行判断读取,效率提升
if cls.instance:
# 判断instance是不是空
return cls.instance
# 不是空返回 instance
with cls.lock:
# 遇到 多线程 使用单例模式 创建一把锁,不会出现内存地址不同
if cls.instance:
# 判断instance是不是空
return cls.instance
# 不是空返回 instance
cls.instance = object.__new__(cls)
# 如果是空 创建一个空对像
return cls.instance
# 创建完毕将创建的空对象返回
基于模块导入的单例模式:
1.第一个py文件
class 类名(object):
def __init__(self):
pass
实例对象a1 = 类名() # 实例化对象
2.第二个py文件
from xxx import 实例对象a1 # 导入第一个py文件的实例化对象
实例对象a1.方法
当进行导入时,实例化对象a1就会存储在内存中,无论导入多少次,都是从内存中进行调用。实现模块级单例模式
创建模式总结
抽象工厂模式和创建工厂模式相对于简单工厂模式和工厂方法而言更为简单和灵活也更为复杂
通常情况下,设计简单工厂模式或者工厂方法模式开始,当发现设计需要更为灵活性时,则向更浮在的设计模式演化。
3.结构型模式
统一将几个对象几个类统一的整合一起使用
适配器模式
结构型模式:几个类组成一个什么结构
适配器模式:原本由于接口不兼容而不能一起工作的哪些类可以一起工作
实现方式:
1.类适配器:使用多继承/利用继承原理
2.对象适配器:使用组合/利用多态
适配器的目的:保持接口一直,复用之前的源代码
# 类的组合使用:
是将A类的对象,放入b类中
class A: # A类
pass
class B: # b类
def ——init——(self,a):
self.a = a() # 放入A类的对象
def dunc(self):
self.a.xxx() # 就可以进行调用A类中的方法,如果存在多个类b,d,e,都可以传入B类中的inita参数中进行调用。
角色:
1.目标接口
2.待适配器类
3.适配器
使用场景:
1.类适配器:如果一个类已经存在,但是接口不符合要就,就可以使用
2.对象适配器:如果存在多个类,但是多个类接口不符合要求,就可以使用
1.类适配器代码(适用于少量待适配器类)
import abc
# 接口类,规定支付接口按照这种模式取设置
class Payment(metaclass=abc.ABCMeta): # 目标接口
@abc.abstractmethod
def pay(self, money):
pass
# 继承抽象类
class Weixinpay(Payment): # 抽象类/按照接口设置的类
def pay(self, money):
print("微信支付{}元".format(money))
# 待适配器类:与目标接口设置不符合,使用类适配器
class BankPay:
def cost(self, money):
print("银联支付{}".format(money))
# 类适配器
class NweBankPay(Payment, BankPay):
def pay(self, money):
self.cost(money)
# 调用时:调用适配器中的方法就可以
b = BankPay() # 调用适配
b.pay(100)
# 类适配器的原理:
利用了继承的特性,子类没有找父类的规则。
适配类中:
1.继承接口类,设置好规定的接口
2.继承待适配器类,适配器需要利用self调用待适配器类中的方法,进行使用
2.对象适配器/其他待适配器对象中的方法是一致的(适用于大量待适配器类)
import abc
# 接口类,规定支付接口按照这种模式取设置
class Payment(metaclass=abc.ABCMeta): # 目标接口
@abc.abstractmethod
def pay(self, money):
pass
# 继承抽象类
class Weixinpay(Payment): # 抽象类/按照接口设置的类
def pay(self, money):
print("微信支付{}元".format(money))
# 待适配器类:与目标接口设置不符合,使用类适配器
class BankPay:
def cost(self, money):
print("银联支付{}".format(money))
# 对象适配器
class PaymentAdapter(Payment): # 继承接口类
# 写一个__init__方法
def __init__(self,payment):
# 加括号接受类名/不加括号接受类对象
self.payment=payment() # 这个参数就是接受待适配器类的类名
# 接口类规定的写法
def pay(self, money):
self.payment.cost(money) # 代用待适配器类中的方法
# 调用
p = PaymentAdapter(BankPay) # 将待适配器类名传入
p.pay(100) #代用对象适配器中的方法
桥模式
将一个的事物的两个维度分开,使其能够独立分开
例如:一幅画,需要颜色和图案内容,这就是两个维度。
角色:
抽象
细化抽象
实现者
具体实现者
应用场景:
当事物有两个维度的表现,两个维度可以扩展时
优点:
抽象和实现相分离
优秀的扩展能力
桥模式和对象适配器模式几乎相同。
代码实例:
import abc
# 形状类 接口/抽象
class Shape(metaclass=abc.ABCMeta):
def __init__(self, color):
self.color = color # 初始化一个实例变量/而这个实例变量时颜色类接口
@abc.abstractmethod
def deaw(self):
pass
# 颜色类 接口/细化
class Color(metaclass=abc.ABCMeta):
@abc.abstractmethod
def paint(self, shape):
pass
# 实现的具体形状类/抽象实现者
class Rectangle(Shape):
name = '长方形'
# 长方形逻辑
def deaw(self): # 因为接口类有init方法实例变量,可以通过变量调用
self.color.paint(self) # color = Red()类对象.方法
# 当调用deaw方法时。在这就直接执行了颜色类中paint方法将自己传入中
# 实现颜色具体/细化实现者
class Red(Color):
def paint(self, shape):# shape参数接受的是抽象者的本身对象
print('红颜色{}'.format(shape.name)) # shape.name就是调用本身的类变量
r = Rectangle(Red()) # 传入的颜色对象
r.deaw()
'''
如实例:
利用形象类中的init方法中写入一个实例对象的参数,而这个实例对象参数就负责接受具体颜色实现的类。
逻辑方式:
1.设置不同的两个维度的接口类,在其中一个接口类中设置init方法
2.创建两个接口具体实现的类
3.实例化抽象这,将细化者对象当参数传入到抽象这中,在利用实例化对象调用抽象者的方法
'''
记忆:
图形类中,init /color变量 = 颜色类实例对象
颜色类实例对象中的方法:paint接受了一个参数,就是图像类本身
1.实例化图像类,将颜色类当对象传入
图像类的执行
图像类的方法:deaw,调用了父类color变量,
因为:color变量 = 颜色类实例对象,索引直接调用了颜色类的方法paint并且将图像类本身对象传入到颜色类paint方法中
2.在颜色类中paint方法
直接调用设置的变量shape,而这个变量本身就是图像类的对象,直接使用了内部的类变量
3.在实例化对象.deaw(),就打印了红色的长方形
4.组合模式(属性结构时)
概念:将对象组成树形结构,以表示‘部分-整体’的层次结构,组合模式,是的用户对单个对象和组合对象的使用具有统一性。
角色:
抽象组件
叶子组件
复合组件
客户端
使用场景:
1.表对象的部分-整体的层次结构(特别结构是递归)
2.希望用户忽略组件对象与单个对象的不同,用户统一的使用组件结构的所有对象
优点:
1.带那个一包含基本对象和组合对象的类的层次结构
2.简化了客户端代码,即客户端可以一致的使用组合对象和单个对象
3.更容易增加新类型组件
代码实例
import abc
# 设置一个接口
class Graphic(metaclass=abc.ABCMeta):
@abc.abstractmethod
def deaw(self):
pass
# 设置一个叶子叶子组件/底层的
class Point(Graphic): # 点类
def __init__(self, x, y):
self.x = x
self.y = y
def deaw(self):
# 简单图形
print(self)
# 打印对象,如果类中带有str方法,就会打印对应返回的值
# 如果没有str方法,就会打印对象本身
def __str__(self):
return "A:{}B:{}".format(self.x, self.y)
# 叶子组件的调用方式
p = Point(1,2)
p.deaw()
# 设置一个组合类/接受的是叶子类的对象。可以说处理叶子类的一个类方式/高级的
class Picture(Graphic):
def __init__(self, li):
self.children = [] # 列表
for i in li: # 支持列表对象
self.add(i)
def add(self, graphic):
self.children.append(graphic)
def deaw(self):
# 复杂图形
for g in self.children: # 递归
g.deaw()
# 组合组件掉用方式
p1 = Point(1, 2)
p2 = Point(1, 2)
p4 = Point(1, 2)
p5 = Point(1, 2)
n = Picture([p1,p2,p4,p5])
n.deaw()
组合模式:其实就是,先设置一个简单的叶子类,主要负责代码的呈现,而组合类就负责将叶子类对象进行内部调用。而叶子类与组合类同时使用的是同一个接口类
只不过组合类比叶子类更为高级。
外观模式(非常简单模式)
给一套系统按配件设置接口,在定义一个高级接口,负责处理系统的配件接口
定义:为子系统中的一组接口提供一个统一的界面,外观模式定义了一个高层的接口,这个即可使整个子系统更加容易使用
角色:
外观类
子系统类
目的:不让用户直接操作子系统类,封装一个高层的代码负责封装子系统类的方法
优点:
1.减少系统的相互依赖
2.提高灵活
3.提高安全性
代码实例
import abc
# 一个接口
class Exterior(metaclass=abc.ABCMeta):
@abc.abstractmethod
def start(self):
pass
@abc.abstractmethod
def finish(self):
pass
# 子系统
class CPU(Exterior):
def start(self):
print('开启cpu')
def finish(self):
print('关闭cpu')
# 子系统
class Hard_Disk(Exterior):
def start(self):
print("开启硬盘")
def finish(self):
print("关闭硬盘")
# 外观类
class Computer(Exterior):
# 在外观类中直接实例化 上面两个子类,不讲子类暴露在外部
def __init__(self):
self.cpu = CPU()
self.hard_disk = Hard_Disk()
def start(self):
self.cpu.start() # 调用子类对象的方法
self.hard_disk.start()
def finish(self):
self.cpu.finish()
self.hard_disk.finish()
# 使用外观类进行嗲用 子类的内容.
d = Computer()
d.finish()
代理模式
概念:为其他对象提供一种代理控制对这个对象的访问
应用场景
远程代理:为远程的对象提供对象
数据在远程服务器,利用一个类去获取远程服务器的数据
虚拟代理:根据需要创建很大的对象/可以较少内存的开销
根据需要创建一个很大的对象,例如浏览器无图模式,只有点击图片才能显示图片的详情
保护代理:控制对象原始对象的访问,用于对象有不同访问权限
角色:
抽象实体:接口目的:使实现的细节的类,具有统一的接口方法
实体:
代理类:
优势:
远程代理:可以隐藏对象位于远程地址的空间事实
虚代理:可以优化内存,例如:根据要求创建对象
保护代理:在访问对象时,有一些内务的处理
import abc
# 代理需要现有实例
# 创建接口
class Subject(metaclass=abc.ABCMeta):
@abc.abstractmethod
def get_content(self):
pass
@abc.abstractmethod
def set_content(self, content): # 真是的与代理的用时时相同的
pass
# 真是的对象,不加入代理/真实代理
class RealSubject(Subject):
def __init__(self, filename):
# filename 文件名称
self.filename = filename # 文件名称
f = open(filename, "r", encoding="utf-8")
self.content = f.read() # 读取文件
f.close() # 关闭文件
def get_content(self): # 阅读文件
return self.content # 直接读取文件
def set_content(self, content):
# 写入文件,content 是写入文件的内容
f = open(self.filename, "r", encoding="utf-8")
f.write(content)
f.close()
# 直接使用真是对象
r = RealSubject('xx.text') # 不执行类中的方法,但是一直占用着电脑内存
# 虚代理
# 根据需要调用对象,如果用户没有需要/就必要创建对象,占用内存
class VirualProxy(Subject):
def __init__(self, filename):
self.filename = filename # 文件对象/只是存储文件名字符串/没有真的读取
self.subj = None # 真是对象
# 读取
def get_content(self):
# 虚代理,如果调用这个方法后,先判断subj有没有值
# 没有值就实例化一个真正的对象,将文件名实例变量传入
if not self.subj:
self.subj = RealSubject(self.filename) # 这个时候,subj就是RealSubject的实例化对象
return self.subj.get_content() # 直接调用RealSubject类中的get_content方法/相当于这个虚代理就拥有了读取的方法
# 写入
def set_content(self, content):
if not self.subj: # 优先判断subj这个参数有没有实例化对象
self.subj = RealSubject(self.filename)
return self.subj.set_content(content)
# 保护代理/只能直接读文件/根据条件判断用户是否有权限写入
class PortectedProxy(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('没有权限')
虚代理:使用后,在没有调用当前方法时,没回占用内存
保护代理:用户只有读的权利,没有写的权利,需要根据用户是否存在权限
5.行为型模式
责任链模式
内容:
使用多个对象都有集合处理请求,从而避免请求的发送者和就守着之间的耦合关系
将对象连成一条链子,并且沿着链子进行传递请求,知道有一个对象处理他为止
角色:
抽象处理者
具体处理者
客户端
使用场景:
有多个对象可以处理一个请求,那个请求处理根据逻辑而定
在不明白接受者情况下时,向多个对象中的一个提交一个请求
优点:
降低耦合度:一个对象无序知道其他哪一个对象处理请求(高层代码不需要知道怎么处理,只需要传递第一个就可以)
就如公司请假一样
我 - 组长 - 经理 -总经理 -董事长
代码案例
import abc
class Abstract(metaclass=abc.ABCMeta):
@abc.abstractmethod
def fake(self, day):
pass
# 第3层
class Manager(Abstract):
def fake(self, day):
if day <= 10:
print("经理批假{}".format(day))
else:
print("经理不批")
# 第2层
class Group_leader(Abstract):
def __init__(self):
self.nuxe = Manager()
def fake(self, day):
if day <= 5:
print("组长批假{}".format(day))
else:
print("组长不批,找经理批")
self.nuxe.fake(day)
# 第1层
class Small_Group_leader(Abstract):
def __init__(self):
self.nuxe = Group_leader()
def fake(self, day):
if day <= 5:
print("小组长批假{}".format(day))
else:
print("小组长不批,找组长批")
self.nuxe.fake(day)
s = Small_Group_leader()
s.fake(1)
# 不需要知道传入的对象是谁处理的,只需要将对象传给第1层类就可以,一层一层执行,知道处理完毕
观察者模式(用的比较多/发布订阅模式)
用的比较多
内容:
定义对象键的一种一对多依赖关系,当对象的状态发生变化,所有依赖的对象都会被通知并且被更新。
观察者模式:发布订阅模式
角色:
抽象主题
具体主题 -- 发布者
抽象观察者
具体观察者 -- 订阅者
使用场景:
当抽象模型有两个方面,其中一个方面依赖另一个方面,将这两个封装在一个独立对象中,以可以独立改变和复用
当对一个对象的改变需要同时改变其他对象,而不知道具体改变多少
当一个对象需要通知其他对象,而他又不能嘉定其他对象是谁
有点:
耦合小
支持支持广播通信
实例代码
import abc
# 抽象类/抽象的订阅者
class Observer(metaclass=abc.ABCMeta):
@abc.abstractmethod
def update(self, notice):
pass
# 抽象的发布者
class Notice:
def __init__(self):
self.obserbers = []
def attach(self, obs): # 添加
self.obserbers.append(obs)
def detach(self, obs): # 删除
self.obserbers.reverse(obs)
def notify(self): # 执行订阅者中的方法/相当于一个推送方法
for obs in self.obserbers:
obs.update(self) # 将自己本身类传入到了订阅者实现类方法中
class StaffNotice(Notice): # 发布者实现
def __init__(self, company=None):
super().__init__() # 掉用父类的__init__方法,防止重用问题
self.company = company # 可以传可以不传,默认为none
@property
def company_info(self):
return self.__company_info # 设置一个私有属性
@company_info.setter # 负责写/使用了setter就对company_info进行了写入info参数接受被写入的值
def company_info(self, info):
# info 就是被写入的文本信息
self.__company_info = info # 进行赋值
self.notify() # 推送,观察者 只一个操作是重点
class Staff(Observer): # 订阅者
def __init__(self):
self.company_info = None
def update(self, notice):
# notice 就是Notice类中方法notify的对象self
self.company_info = notice.company_info # company_info方法
n = StaffNotice('公司123') # 发布者/公司123传入到init company变量中
s1 = Staff() # 订阅者
n.attach(s1) # 将订阅者添加到列表中
n.company_info = '加入' # 将 参数写入到__company_info中info中
print(s1.company_info)
策略者模式(算法)
内容
定义系列算法,把他们一个个封装起来,并且使用他们可以相互替换
模式可以使算法可以独立使它的客户而变化(根据客户变化而变化)
角色
抽象策略
具体策略
上下文
优点:
定义了一些列的可以重用的算法和行为
消除了一些条件语句
可以提供相同行为的不同实现
缺点
客户必须列表不同的策略
代码
import abc
# 抽象策略
class Stra(metaclass=abc.ABCMeta):
@abc.abstractmethod
def execute(self, data):
pass
# 实现策略
class Fast(Stra):
def execute(self, data):
print('较快{}'.format(data))
# 实现策略
class Slow(Stra):
def execute(self, data):
print('较慢{}'.format(data))
# 上下文类/将数据和策略放在一个类中/不需要用户知道的数据
class Context:
def __init__(self,strategy,data):
self.strategy =strategy
self.data =data
def set_strategy(self,strategy): # 切换策略
self.strategy = strategy
def do_strategy(self): # 执行策略
self.strategy.execute(self.data)
data ='....'
s1 = Fast() # 快的
s2 = Slow() # 满的
c = Context(s1,data)
c.do_strategy()
# 如果需要进行切换策略,直接调用set_strategy方法,值不会变化
c.set_strategy(s2)
c.do_strategy()
模板方法模式(算法)
定义一个操作中的算法骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变算法的结构课重新定义算法的某些步骤
角色:
抽象类:定义抽象类的原子操作(钩子操作),实现一个模板方法,作为算法骨架
具体类:实现钩子方法的操作
场景:
一次性实现一个算法部分不变的部分
各个子类中的公共行为应该别提取出来集中到一个公共的父类中,避免代码重复
控制子类扩展
代码
import abc
import time
class window(metaclass=abc.ABCMeta):
@abc.abstractmethod
def start(self): # 开始/原子操作/钩子操作/大逻辑不用重复的书写
pass
@abc.abstractmethod
def reqaint(self): # 刷新
pass
@abc.abstractmethod
def sopt(self): # 停止
pass
# 模板方法/具体方法
def run(self):
self.start()
while True:
try:
self.reqaint()
time.sleep(1)
except KeyboardInterrupt:
break
self.sopt()
class A(window):
def __init__(self, msg):
self.msg = msg
def start(self):
print('窗口开始运行')
def sopt(self):
print('窗口关闭')
def reqaint(self):
print(self.msg)
a = A('.....')
a.run() # 直接运行模板方法
3.设计模式总结总结
如果自己的代码需要被别人使用:开源框架,或者公司的项目时就需要使用设计模式,使代码看起来更为简洁,更具有逻辑性。