常见设计模式-Python实现

文章目录

  • 1. 概述
    • 1.1 概念
    • 1.2 代码
    • 1.3 结果
  • 2. 面向对象设计原则
    • 2.1 设计原则
    • 2.2 设计模式分类
  • 3. 简单工厂模式
  • 4. 工厂方法模式
  • 5. 抽象工厂模式
  • 6. 建造者模式
  • 7. 单例模式
  • 8. 适配器模式
  • 9. 桥模式
  • 10. 组合模式
  • 11. 外观模式
  • 12. 代理模式
  • 13. 责任链模式
  • 14. 观察者模式
  • 15. 策略者模式
  • 16. 模板方法模式
  • 17. 状态模式

1. 概述

1.1 概念

设计模式:对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。每一个设计模式系统地命名,解释和评价了面向对象系统中一个重要的和重复出现的设计

  • 推荐书籍:设计模式:可复用面向对象软件的基础
  • 面向对象三大特性:封装,继承,多态
  • 接口:若干抽象方法的集合;作用:限制实现接口的类必须按照接口给定的调用方式实现这些方法,对高层模块隐藏了类的内部实现。

1.2 代码

# 1.导入抽象基类,让子类必须要实现该方法,
#  只是抽象方法,并不实现功能,只能继承,不能被实例化
from abc import ABCMeta, abstractmethod


# 2.定义接口类
# Payment 是一个抽象类,定义了一个pay的抽象方法
# 通过抽象方法,可以规范其子类在用此方法的接口规范
class Payment(metaclass=ABCMeta):
	@abstractmethod
	# 定义接口抽象方法
	def pay(self, money):
		pass

# 3.定义子类Alipay来继承接口抽象类
class Alipay(Payment):
	# 子类继承父类方法,接口保持一致
	def pay(self, money):
		print("alipay=%d" % money)


# 4.定义子类Wechatpay来继承接口抽象类
class WechatPay(Payment):
	def pay(self, money):
		print("wechatpay=%d" % money)


# 5.实例化子类对象
alipay_test = Alipay()
wechat_test = WechatPay()

# 6.调用子类的方法
alipay_test.pay(200)
wechat_test.pay(100)

1.3 结果

alipay=200
wechatpay=100

2. 面向对象设计原则

2.1 设计原则

  • 开放封闭原则:一个软件实体如类,模块和函数应该对扩展开放,对修改关闭,即软件实体应尽量在不修改原有代码的情况下进行扩展。
  • 里氏替换原则:所有引用父类的地方必须能透明地使用其子类的对象
  • 依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象,抽象不应该依赖细节,细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程。
  • 接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口
  • 单一职责原则:不要存在多于一个导致类变更的原因,通俗的说,一个类只负责一项职责

2.2 设计模式分类

  • 创新型模式(5种):工厂方法模式,抽象工厂模式,创建者模式,原型模式,单例模式
  • 结构型模式(7种):适配器模式,桥模式,组合模式,装饰模式,外观模式,享元模式,代理模式
  • 行为型模式(11种):解释器模式,责任链模式,命令模式,迭代器模式,中介者模式,备忘录模式,观察者模式,状态模式,策略模式,访问者模式,模板方法模式

3. 简单工厂模式

  • 内容:
    不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例
  • 角色:
    (1) 工厂角色; (2)抽象产品角色; (3)具体产品角色
  • 优点
    (1)隐藏了对象创建的实现细节
    (2)客户端不需要修改代码
  • 缺点:
    (1)违反了单一职责原则,将创建逻辑集中到一个工厂类里
    (2)当添加新产品时,需要修改工厂类代码,违反了开闭原则
  • 代码
from abc import ABCMeta, abstractmethod


# 抽象接口,负责所有的支付接口的样式
class Payment(metaclass=ABCMeta):
	@abstractmethod
	def pay(self, money):
		pass


# 阿里支付,继承payment
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 PaymentFactory:
	def create_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 class named %s" % method)


pf = PaymentFactory()
p = pf.create_payment('huabei')
p.pay(1000)
# 输出
#花呗支付1000元.

4. 工厂方法模式

  • 内容:
    定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类
    (1)抽象工厂角色(creator)
    (2)具体工厂角色(concrete creator)
    (3)抽象产品角色(product)
    (4)具体产品角色(concrete product)

  • 类图继承
    常见设计模式-Python实现_第1张图片

  • 优点:
    (1)每个具体产品都对应一个具体工厂类,不需要修改工厂代码
    (2)隐藏了对象创建的实现细节

  • 缺点:
    (1)每增加一个具体产品类,就必须增加一个相应的具体工厂类

  • 代码

from abc import ABCMeta, abstractmethod


# 抽象接口(支付);负责所有的支付接口的样式
class Payment(metaclass=ABCMeta):
	@abstractmethod
	def pay(self, money):
		pass


# 阿里支付,继承payment
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)

# 微信支付,继承payment
class WechatPay(Payment):
	def pay(self, money):
		print("微信支付%d元." % money)

# 银联支付,继承payment
class BankPay(Payment):
	def pay(self, money):
		print("银联支付%d元." % money)


# 抽象接口(支付工厂);负责实例化类
class PaymentFactory(metaclass=ABCMeta):
	@abstractmethod
	def create_payment(self):
		pass

# 阿里支付工厂类,继承自 PaymentFactory
class AlipayFactory(PaymentFactory):
	def create_payment(self):
		return Alipay()

# 微信支付工厂类,继承自 PaymentFactory
class WechatPayFactory(PaymentFactory):
	def create_payment(self):
		return WechatPay()

# 花呗支付工厂类,继承自 PaymentFactory
class HuabeiFactory(PaymentFactory):
	def create_payment(self):
		return Alipay(use_huabei=True)

# 银联支付工厂类,继承自 PaymentFactory
class BankPayFactory(PaymentFactory):
	def create_payment(self):
		return BankPay()


# HuabeiFactory -> Alipay(use_huabei=True) -> pay
hua_factory = HuabeiFactory()
hua_pay = hua_factory.create_payment()
hua_pay.pay(200)

bank_facotry = BankPayFactory()
bank_pay = bank_facotry.create_payment()
bank_pay.pay(300)

ali_factory = AlipayFactory()
ali_pay = ali_factory.create_payment()
ali_pay.pay(400)


we_factory = WechatPayFactory()
we_pay = we_factory.create_payment()
we_pay.pay(500)
  • 结果
花呗支付200.
银联支付300.
支付宝支付400.
微信支付500.

5. 抽象工厂模式

  • 内容:
    定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象
    例:生产一部手机,需要手机壳,CPU,操作系统三类对象进行组装,其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象
  • 相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一套产品
  • 优点:
    (1)将客户端与类的具体实现相分离
    (2)每个工厂创建了一个完整的产品系列,是的易于交换产品系列
    (3)有利于产品的一致性(即产品之间的约束关系)
  • 缺点:
    难以支持新种类的(抽象)产品
  • 代码
# -*- coding: utf-8 -*-
# @Project: zc
# @Author: zc
# @File name: abstract_factory
# @Create time: 2022/1/16 11:55


# 1.导入相关数据库
from abc import abstractmethod, ABCMeta


# 2. 手机壳抽象类
class PhoneShell(metaclass=ABCMeta):
	@abstractmethod
	def show_shell(self):
		pass


# 3. CPU抽象类
class CPU(metaclass=ABCMeta):
	@abstractmethod
	def show_cpu(self):
		pass


# 4.系统抽象类
class OS(metaclass=ABCMeta):
	@abstractmethod
	def show_os(self):
		pass


# 5. 工厂抽象类
class PhoneFactory(metaclass=ABCMeta):
	@abstractmethod
	def make_shell(self):
		pass

	@abstractmethod
	def make_cpu(self):
		pass

	@abstractmethod
	def make_os(self):
		pass


# 6.具体类;小手机壳
class SmallShell(PhoneShell):
	def show_shell(self):
		print("普通手机小手机壳")


# 7.具体类:大手机壳
class BigShell(PhoneShell):
	def show_shell(self):
		print("普通手机大手机壳")


# 8.具体类:苹果手机壳
class AppleShell(PhoneShell):
	def show_shell(self):
		print("苹果手机壳")


# 9.具体类: 晓龙CPU
class SnapDragonCPU(CPU):
	def show_cpu(self):
		print("晓龙CPU")


# 10.具体类:联发科CPU
class MediaTekCPU(CPU):
	def show_cpu(self):
		print("联发科CPU")


# 11.具体类:苹果CPU
class AppleCPU(CPU):
	def show_cpu(self):
		print("苹果CPU")


# 12.具体类:安卓系统
class Android(OS):
	def show_os(self):
		print("Android系统")


# 13. 具体类:苹果系统
class IOS(OS):
	def show_os(self):
		print("IOS系统")


# 14. 具体类:小米工厂
class MiFactory(PhoneFactory):
	def __init__(self):
		print("*" * 20)
		print("mi_start")
		print("xiaomifactory")

	def make_shell(self):
		return BigShell()

	def make_cpu(self):
		return SnapDragonCPU()

	def make_os(self):
		return Android()


# 具体类:华为工厂
class HuaweiFactory(PhoneFactory):
	def __init__(self):
		print("*" * 20)
		print("huawei_start")
		print("huaweifactory")

	def make_shell(self):
		return SmallShell()

	def make_cpu(self):
		return MediaTekCPU()

	def make_os(self):
		return Android()


# 具体类:苹果工厂
class IPhoneFactory(PhoneFactory):
	def __init__(self):
		print("*" * 20)
		print("Apple_start")
		print("Apple_factory")

	def make_cpu(self):
		return AppleCPU()

	def make_os(self):
		return IOS()

	def make_shell(self):
		return AppleShell()


# 手机类,收集工厂手机信息,返回相关结果
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()
		print("*" * 20)
		print('\n')


def make_phone(factory):
	cpu = factory.make_cpu()
	os = factory.make_os()
	shell = factory.make_shell()
	return Phone(cpu, os, shell)


xiaomi_phone = make_phone(MiFactory())
xiaomi_phone.show_info()

huawei_phone = make_phone(HuaweiFactory())
huawei_phone.show_info()

apple_phone = make_phone(IPhoneFactory())
apple_phone.show_info()
  • 结果
********************
mi_start
xiaomifactory
手机信息:
晓龙CPU
Android系统
普通手机大手机壳
********************


********************
huawei_start
huaweifactory
手机信息:
联发科CPU
Android系统
普通手机小手机壳
********************


********************
Apple_start
Apple_factory
手机信息:
苹果CPU
IOS系统
苹果手机壳
********************

6. 建造者模式

  • 内容:
    将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的标识
  • 角色:
    (1)抽象建造者(Builder)
    (2)具体建造者(Concrete Builder)
    (3)指挥者(Director)
    (4)产品(Product)
  • 建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者欧式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象
  • 优点:
    (1)隐藏了一个产品的内部结构和装配过程
    (2)将构造代码与表示代码分开
    (3)可以对构造过程进行更精细的控制
  • 代码
# -*- coding: utf-8 -*-
# @Project: zc
# @Author: zc
# @File name: constructor_mode_test
# @Create time: 2022/1/16 16:06


from abc import abstractmethod, ABCMeta


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)


# 抽象建造者(Builder)
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


# 具体建造者(concrete builder)
class SexGirlBuilder(PlayerBuilder):
	def __init__(self):
		self.player = Player()

	def build_face(self):
		self.player.face = "sex_face"

	def build_body(self):
		self.player.body = "sex_body"

	def build_arm(self):
		self.player.arm = "sex_arm"

	def build_leg(self):
		self.player.leg = "sex_leg"

# 具体建造者(concrete builder)
class MonsterBuilder(PlayerBuilder):
	def __init__(self):
		self.player = Player()

	def build_face(self):
		self.player.face = "monster_face"

	def build_body(self):
		self.player.body = "monster_body"

	def build_arm(self):
		self.player.arm = "monster_arm"

	def build_leg(self):
		self.player.leg = "monster_leg"


# 指挥者(Director)
class PlayerDirector:
	def build_player(self, builder):
		builder.build_body()
		builder.build_face()
		builder.build_arm()
		builder.build_leg()
		return builder.player


# client

sex_builder = SexGirlBuilder()
director = PlayerDirector()
director_sex = director.build_player(sex_builder)
print(director_sex)

monster_builder = MonsterBuilder()
director_monster = director.build_player(monster_builder)
print(director_monster)
  • 结果
sex_face,sex_body,sex_arm,sex_leg
monster_face,monster_body,monster_arm,monster_leg

7. 单例模式

  • 内容:保证一个类只有一个实例,并提供一个访问它的全局访问点
  • 角色:单例(Singleton)
  • 优点:
    (1)对唯一实例的受控访问
    (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, word):
		self.word = word


# 创建实例a,b
a = MyClass(100)
b = MyClass(200)
print(f'a.word={a.word}')
print(f'b.word={b.word}')

# 因为是单例模式,所以a的值会被b的值取代掉,这样就只有一个实例了

print(f'id(a)==id(b) is {id(a) == id(b)}')
  • 结果:
a.word=200
b.word=200
id(a)==id(b) is True
  • 小结:
    (1)抽象工厂模式和建造者模式相比于简单工厂模式和工厂方法模式而言更灵活也更复杂
    (2)通常情况下,设计以简单工厂模式后工厂方法模式开始,当你发现设计需要更大的灵活性时,则像更复杂的设计模式演化。

8. 适配器模式

  • 内容:
    将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
  • 实现方式:
    (1)类适配器:使用多继承
    (2)对象适配器:使用组合
  • 角色:
    (1)目标接口(Target)
    (2)待适配的类(Adaptee)
    (3)适配器(Adapter)
  • 使用场景:
    (1)想使用一个已经存在的类,而它的接口不符合你的要求
    (2)(对象适配器)想使用一些已经存在的子类,但不可能对每一个都进行子类化以匹配它们的接口,对象适配器可以适配它的父类接口。
from abc import abstractmethod, ABCMeta


class Payment(metaclass=ABCMeta):
	@abstractmethod
	def pay(self, money):
		pass


class Alipay(Payment):
	def pay(self, money):
		print("alipay is %d" % money)


class Wechat(Payment):
	def pay(self, money):
		print("wechat is %d" % money)


class Bankpay:
	def cost(self, money):
		print("the cost is %d" % money)


class Applepay:
	def cost(self, money):
		print("the cost is %d" % money)


# 对象适配器
class PaymentAdaptor(Payment):
	def __init__(self, payment):
		self.payment = payment

	def pay(self, money):
		self.payment.cost(money)


p = PaymentAdaptor(Applepay())
p.pay(100)

9. 桥模式

  • 内容:将一个事物的两个维度分离,使其都可以独立地变化
  • 角色:
    (1)抽象(abstraction);形状
    (2)细化抽象(refinedabstraction);直线,圆形,长方形等
    (3)实现者(implementor);颜色
    (4)具体实现者(concreteimplementor);红色,蓝色,绿色等
  • 注解:
    将实现与抽象相分离,在代码中,"形状"是抽象,颜色是实现,代码本身的逻辑是要在实现者中实现的;细化抽象指的是长方形,圆形,直线等对象。
  • 应用场景:
    当事物有两个维度上的表现,两个维度都可能扩展时。
  • 优点:
    (1)抽象和实现相分离
    (2)优秀的扩展能力
  • 代码
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):
		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 Yellow(Color):
	def paint(self, shape):
		print("黄色的%s" % shape.name)


shape_1 = Rectangle(Red())
shape_1.draw()
shape_2 = Circle(Green())
shape_2.draw()
shape_3 = Line(Yellow())
shape_3.draw()
  • 结果
红色的长方形
蓝色的圆形
黄色的直线

10. 组合模式

  • 内容:将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性
  • 角色:
    (1)抽象组件(Component)
    (2)叶子组件(leaf)
    (3)复合组件(Composite)
    (4)客户端(client)
  • 使用场景:
    (1)表示对象的“部分-整体”层次结构(特别是结构是递归的)
    (2)希望用户忽略组合对象与单个对象的不同,用户统一地使用组合结构中的所有对象
  • 优点:
    (1)定义了包含基本对象和组合对象的类层次结构
    (2)简化客户端代码,即客户端可以一致地使用组合对象和单个对象
    (3)更容易增加新类型的组件
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 "line[%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)
line_1 = Line(Point(0, 0), Point(6, 6))
line_2 = Line(Point(2, 2), Point(8, 8))
pic_1 = Picture([p1, line_1, line_2])
pic_2 = Picture([p1, line_1, line_2])
pc_1 = Picture([pic_1, pic_2])
pc_1.draw()
  • 结果
----------复合图形------
----------复合图形------(2 , 3)
line[(0 , 0),(6 , 6)]
line[(2 , 2),(8 , 8)]
----------复合图形------
----------复合图形------(2 , 3)
line[(0 , 0),(6 , 6)]
line[(2 , 2),(8 , 8)]
----------复合图形------
----------复合图形------

11. 外观模式

  • 内容:
    为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
  • 角色:
    (1)外观(facade)
    (2)子系统类(subsystem classes)
  • 优点:
    (1)减少系统相互依赖
    (2)提高了灵活性
    (3)提高了安全性
  • 代码
#子类CPU
class CPU:
	def run(self):
		print("CPU is run")

	def stop(self):
		print("CPU is stop")

# 子类disk
class Disk:
	def run(self):
		print("Disk is run")

	def stop(self):
		print("Disk is stop")

# 子类memory
class Memory:
	def run(self):
		print("Memory is run")

	def stop(self):
		print("Memory is stop")


# 外观模式的外观就是computer类
class Computer:
	def __init__(self):
		self.cpu = CPU()
		self.disk = Disk()
		self.memory = Memory()

	def run(self):
		print("computer is run")
		self.cpu.run()
		self.disk.run()
		self.memory.run()
		print("computer is run\n")

	def stop(self):
		print("computer is stop")
		self.cpu.stop()
		self.disk.stop()
		self.memory.stop()
		print("computer is stop\n")


computer1 = Computer()
computer1.run()
computer1.stop()
  • 代码:
computer is run
CPU is run 
Disk is run
Memory is run
computer is run

computer is stop
CPU is stop
Disk is stop
Memory is stop
computer is stop

12. 代理模式

  • 内容:为其他对象提供一种代理以控制对这个对象的访问。
  • 应用场景:
    (1)远程代理:为远程的对象提供代理
    (2)虚代理:根据需要创建很大的对象
    (3)保护代理:控制对原始对象的访问,用于对象有不同访问权限时。
  • 角色
    (1)抽象实体(subject)
    (2)实体(realsubject)
    (3)代理(proxy)
  • 优点:
    (1)远程代理:可以隐藏对象位于远程地址空间的事实
    (2)虚代理:可以进行优化,例如根据要求创建对象
    (3)保护代理:允许在访问一个对象时有一些附加的内务处理
  • 代码:
# 导入相关数据库
from abc import abstractmethod, ABCMeta


# 目标:为了让代理的和真实的类对外具有相同的接口
# 抽象对象 subject定义接口
class Subject(metaclass=ABCMeta):
	@abstractmethod
	def get_content(self):
		pass

	@abstractmethod
	def set_content(self, content):
		pass


# 真实对象,继承自Subject
class RealSubject(Subject):
	def __init__(self, filename):
		self.filename = filename
		f = open(self.filename, 'r', encoding='utf-8')
		self.content = f.read()
		f.close()

	def get_content(self):
		print("real_subject")
		return self.content

	def set_content(self, content):
		f = open(self.filename, 'a', encoding='utf-8')
		f.write(content)
		f.close()


# 虚代理,为了解决在用户不执行get_content的时候,就不需要读取文件
# 1. 虚拟代理继承原来真实代理的方法
# 2. 在构造vitualsubject的时候不占用空间来存(self.content)
# 3. 只有用户在调用get_content的时候才读取self.content的信息
class VitualSubject(Subject):
	def __init__(self, filename):
		self.filename = filename
		# self.subj = None 就可以保证默认不调用
		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)


# 保护代理
# 如果我们只想要客户有一个读的权限get_content,不希望有写的权限set_content,
# 那么我们就需要拥戴保护代理模式
class ProtectedProxy(Subject):
	def __init__(self, filename):
		self.subj = RealSubject(filename)

	# 如果想让客户用get_content,那么就直接调用原始的类的方法
	def get_content(self):
		return self.subj.get_content()

	# 如果不想让客户用set_content,那么就抛出权限报错
	def set_content(self, content):
		raise PermissionError("无写入权限")


vitual_sub = VitualSubject("test.txt")
print(f'vitual_sub.get_content()={vitual_sub.get_content()}')
vitual_sub.set_content("vitual-content-add")
print(f'vitual_sub.get_content()={vitual_sub.get_content()}')

protected_sub = ProtectedProxy("test.txt")
print(f'protected_sub.get_content()={protected_sub.get_content()}')
print(f'protected_sub.set_content()={protected_sub.set_content("asdfaf")}')
  • 结果
real_subject
vitual_sub.get_content()=i love you pythonvitual-content-add
real_subject
vitual_sub.get_content()=i love you pythonvitual-content-add
real_subject
protected_sub.get_content()=i love you pythonvitual-content-addvitual-content-add
Traceback (most recent call last):
  File "D:/zc/proxy_patten_test.py", line 146, in <module>
    print(f'protected_sub.set_content()={protected_sub.set_content("asdfaf")}')
  File "D:/zc/proxy_patten_test.py", line 136, in set_content
    raise PermissionError("无写入权限")
PermissionError: 无写入权限
# 注:当我们调用protected_sub.set_content()的时候,我们就会报错,抛出无写入权限异常

13. 责任链模式

责任链模式属于行为型模式

  • 内容:
    使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这些对象连乘一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
  • 角色:
    (1)抽象处理者(handler)
    (2)具体处理者(concretehandle)
    (3)客户端(client)
  • 举例:当我们在公司进行请假处理的时候,我们需要对请假天数进行处理的时候,不同的职位对于天数是不同的处理权限的,所以我们需要用到责任链模式
  • 使用场景:
    (1)有多个对象可以处理一个请求,哪个对象处理由运行时决定
    (2)在不明确接受者的情况下,向多个对象中的一个提交一个请求
  • 优点:
    降低耦合度,一个对象无需知道是其他哪一个对象处理其请求
# 责任链模式通过类的相互传递进行责任链式发展
# 1.导入相关数据库
from abc import abstractmethod, ABCMeta


# 2. 定义通用接口
class Handle(metaclass=ABCMeta):
	@abstractmethod
	def handle(self, day):
		pass


# 3.定义第 一 级别类
class General_Handle(Handle):
	def handle(self, day):
		if day <= 10:
			print("General_Handle is ok for %d" % day)
		else:
			print(" you are ok for leave")


# 4.定义第 二 级别类
class Manager_Handle(Handle):
	def __init__(self):
		self.next = General_Handle()

	def handle(self, day):
		if day <= 5:
			print("Manager_Handle is ok for %d" % day)
		else:
			self.next.handle(day)


# 5.定义第 三 级别类
class Department_Handle(Handle):
	def __init__(self):
		self.next = Manager_Handle()

	def handle(self, day):
		if day <= 1:
			print("Department_Handle is ok for %d" % day)
		else:
			self.next.handle(day)


day_1 = 1
day_5 = 5
day_10 = 10
day_15 = 15
new_handle = Department_Handle()
new_handle.handle(day_1)
new_handle.handle(day_5)
new_handle.handle(day_10)
new_handle.handle(day_15)
  • 结果
Department_Handle is ok for 1
Manager_Handle is ok for 5
General_Handle is ok for 10
 you are ok for leave

14. 观察者模式

  • 内容:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。观察者模式又称“发布-订阅”模式
  • 角色:
    (1)抽象主题(subject)
    (2)具体主题(concrete-subject)-发布者
    (3)抽象观察者(observer)
    (4)具体观察者(concrete-observer) - 订阅者
  • 适用场景:
    (1)当一个抽象模型有两方面,其中一个方面依赖于另一个方面,将这两者封装在独立对象中以使他们可以各自独立地改变和复用
    (2)当对一个 对象的改变需要同事改变其他对象,而不知道具体有多少对象有待改变。
    (3)当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之,你不希望这些对象是紧密耦合的
  • 优点:
    (1)目标和观察者之间是抽象耦合最小
    (2)支持广播通信
  • 举例:
    在我们使用的excel图表中,Excel数据源就相当于发布者,而根据数据源得到的不同的图形,这个不同的图形就相当于订阅者;
  • 要求:
    (1)发布者和订阅者是一对多的关系
    (2)发布者只管自己的发布,订阅者在看到发布者状态更新后,自动更新
    (3)发布者和订阅者之间是松耦合的关系;发布者可以自动的进行订阅者的增加和删除
    常见设计模式-Python实现_第2张图片
  • 代码:
# -*- coding: utf-8 -*-
# @Project: zc
# @Author: zc
# @File name: observe-pattern
# @Create time: 2022/1/22 21:01

# 1.导入相关数据库
from abc import abstractmethod, ABCMeta, ABC


# 2.定义抽象的订阅者接口
class obeserve(metaclass=ABCMeta):
	@abstractmethod
	def update(self, notice):  # notice参数应该是Notice类的对象
		pass


# 3.定义抽象的发布者接口
class Notice:
	def __init__(self):
		self.observe = []

	def attach(self, obs):
		self.observe.append(obs)

	def detach(self, obs):
		self.observe.remove(obs)

	def notify(self):
		for obs in self.observe:
			obs.update(self)


# 4.定义子类,具体的发布者
class Conpany_Notice(Notice):
	def __init__(self, conpany_info=None):
		super().__init__()
		self.__conpany_info = conpany_info

	# 负责返回私有属性
	@property
	def conpany_info(self):
		return self.__conpany_info

	# 重点!!!!
	# 负责写私有属性值,
	# 一旦在更改属性,就自动更新订阅者的信息
	@conpany_info.setter
	def conpany_info(self, info):
		self.__conpany_info = info
		self.notify()


class Staff_Observe(obeserve, ABC):
	def __init__(self):
		self.conpany_info = None

	def update(self, notice):
		self.conpany_info = notice.conpany_info


con_info_1 = "[第一条公告]"
con_info_2 = "[第二条公告]"
con_info_3 = "[第三条公告]"
My_Notice = Conpany_Notice()
staff_1 = Staff_Observe()
staff_2 = Staff_Observe()
My_Notice.attach(staff_1)
My_Notice.attach(staff_2)
print("*" * 30)
print("初始化时的公告")
print(f'staff_1.conpany_info={staff_1.conpany_info}')
print(f'staff_2.conpany_info={staff_2.conpany_info}')
print("*" * 30)
print("\n")
My_Notice.conpany_info = con_info_1
print("*" * 30)
print("第一次更改公告")
print(f'staff_1.conpany_info={staff_1.conpany_info}')
print(f'staff_2.conpany_info={staff_2.conpany_info}')
print("\n")
print("*" * 30)
print("第二次更改公告")
My_Notice.conpany_info = con_info_2
print(f'staff_1.conpany_info={staff_1.conpany_info}')
print(f'staff_2.conpany_info={staff_2.conpany_info}')
print("*" * 30)
print("第三次更改公告,取消staff_2关注")
My_Notice.detach(staff_1)
My_Notice.conpany_info = con_info_3
print(f'staff_1.conpany_info={staff_1.conpany_info}')
print(f'staff_2.conpany_info={staff_2.conpany_info}')
print("*" * 30)
  • 结果
******************************
初始化时的公告
staff_1.conpany_info=None
staff_2.conpany_info=None
******************************


******************************
第一次更改公告
staff_1.conpany_info=[第一条公告]
staff_2.conpany_info=[第一条公告]


******************************
第二次更改公告
staff_1.conpany_info=[第二条公告]
staff_2.conpany_info=[第二条公告]
******************************
第三次更改公告,取消staff_2关注
staff_1.conpany_info=[第二条公告]
staff_2.conpany_info=[第三条公告]
******************************

15. 策略者模式

  • 内容:
    定义一系列的算法,把他们一个个封装起来,并且使他们可相互替换。本模式使得算法可独立于使用它的客户而变化
  • 角色:
    (1)抽象策略(strategy)
    (2)具体策略(concrete-strategy)
    (3)上下文(context);用来链接策略和数据
  • 优点:
    (1)定义了一系列可重用的算法和行为
    (2)消除了一些条件语句
    (3)可以提供相同行为的不同实现
  • 缺点:
    (1)客户必须了解不同的策略
  • 代码:
# -*- coding: utf-8 -*-
# @Project: zc
# @Author: zc
# @File name: strategy_patten
# @Create time: 2022/1/22 22:19

from abc import abstractmethod, ABCMeta


class Stratery(metaclass=ABCMeta):
	@abstractmethod
	def execute(self, data):
		pass


class FastStrategy(Stratery):
	def execute(self, data):
		print("fast_strategy is for  %s " % data)


class LowStrategy(Stratery):
	def execute(self, data):
		print("low_strategy is for %s " % data)


class Contex:
	def __init__(self, strategy, data):
		self.strategy = strategy
		self.data = data

	def set_strategy(self, my_strategy):
		self.strategy = my_strategy

	def do_strategy(self):
		self.strategy.execute(self.data)


my_fast_strategy = FastStrategy()
my_low_strategy = LowStrategy()
my_data = "[....mydata...]"
my_contex = Contex(my_fast_strategy, my_data)
my_contex.do_strategy()
my_contex.set_strategy(my_low_strategy)
my_contex.do_strategy()
  • 结果
fast_strategy is for  [....mydata...] 
low_strategy is for [....mydata...] 

16. 模板方法模式

  • 内容:
    定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可定义该算法的某些特定步骤
  • 角色:
    (1)抽象类(abstract-class):定义抽象的原子操作(钩子操作);实现一个模板方法作为算法的骨架
    (2)具体类(concrete-class):实现原子操作
  • 使用场景:
    (1)一次性实现一个算法的不变的部分
    (2)各个子类的公共行为应该被提取出来并集中到一个公共父类中以避免代码重复
    (3)控制子类的扩展
  • 代码
# -*- coding: utf-8 -*-
# @Project: zc
# @Author: zc
# @File name: template-pattern
# @Create time: 2022/1/23 12:22

# 1.导入相关数据库
from abc import abstractmethod, ABCMeta
from time import sleep


# 2. 定义抽象类接口
class Window(metaclass=ABCMeta):
	@abstractmethod
	def start(self):
		pass

	@abstractmethod
	def stop(self):
		pass

	@abstractmethod
	def repaint(self):
		pass

	# 具体方法就是模板方法框架
	def run(self):
		self.start()
		while True:
			try:
				self.repaint()
				sleep(1)
			except KeyboardInterrupt:
				break
		self.stop()


# 3. 定义子类,具体化父类的原子操作
class MyWindow(Window):
	def __init__(self, msg=None):
		self.msg = msg

	# 定义原子操作
	def start(self):
		print("mywindow is start")

	# 定义原子操作
	def stop(self):
		print("mywindow is stop")

	# 定义原子操作
	def repaint(self):
		print("mywindow is %s" % self.msg)


MyWindow("new_message").run()
  • 结果:
mywindow is start
mywindow is new_message
mywindow is new_message
mywindow is new_message
mywindow is new_message
mywindow is new_message
mywindow is new_message
mywindow is stop

17. 状态模式

  • 定义:
    行为模式关注的是对象的响应性,它们通过对象之间的交互以实现更强大的功能。状态模式是一种行为设计模式。有事也被称为状态模式的对象。在此模式中,一个对象可以基于其内部状态封装多个行为。状态模式也可以看作是在运行时改变对象行为的一种方式
  • 主要结构:
    (1)State:这被认为是封装对象行为的接口。这个行为与对象的状态相关联
    (2)ConcreteState:这是实现State接口的子类。ConcreteState实现与对象的特定状态相关联的实际行为
    (3)Context:这定义了客户感兴趣的接口。Contex还维护了一个ConcreteState子类的实例,该子类在内部定义了对象的特定状态的实现。
  • 代码1:
from abc import ABCMeta, abstractmethod


# 定义通用接口state
class State(metaclass=ABCMeta):
	@abstractmethod
	def handle(self):
		pass


# 定义具体类A继承自接口
class ConcreteStateA(State):
	def handle(self):
		print(f"ConcreteStateA")

# 定义具体类B继承自接口
class ConcreteStateB(State):
	def handle(self):
		print(f"ConcreteStateB")

# 定义上下文类来关联和管理具体类
class Context(State):
	def __init__(self):
		self.state = None

	def get_state(self):
		return self.state

	def set_state(self, state):
		self.state = state

	def handle(self):
		if self.state is None:
			print("None")
		else:
			self.state.handle()


context = Context()
stateA = ConcreteStateA()
stateB = ConcreteStateB()
context.handle()
context.set_state(stateA)
context.handle()
context.set_state(stateB)
context.handle()

输出:

None
ConcreteStateA
ConcreteStateB
  • 代码2:
from abc import ABCMeta, abstractmethod

class State(metaclass=ABCMeta):
	@abstractmethod
	def doThis(self):
		pass


class StartState(State):
	def doThis(self):
		print("TV Switching ON ...")


class StopState(State):
	def doThis(self):
		print("TV Switching OFF...")


class TVContext(State):
	def __init__(self):
		self.state = None

	def get_state(self):
		return self.state

	def set_state(self, state):
		self.state = state

	def doThis(self):
		return self.state.doThis()


context = TVContext()
print(context.get_state())

start = StartState()
stop = StopState()

context.set_state(start)
context.doThis()
context.set_state(stop)
context.doThis()

输出:

None
TV Switching ON ...
TV Switching OFF...
  • 代码3:
class ComputerState(object):
	name = "state"
	allowed = []

	def swicth(self, state):
		if state.name in self.allowed:
			print('Current:', self, '=> switched to new state', state.name)
			self.__class__ = state
		else:
			print('Current:', self, ' => switching to', state.name, 'not possible.')

	def __str__(self):
		return self.name


class Off(ComputerState):
	name = "off"
	allowed = ['on']


class On(ComputerState):
	name = "on"
	allowed = ['off', 'suspend', 'hibernate']


class Suspend(ComputerState):
	name = "suspend"
	allowed = ['on']


class Hibernate(ComputerState):
	name = "hibernate"
	allowed = ['on']


class Computer(object):
	def __init__(self, model='HP'):
		self.model = model
		self.state = Off()

	def change(self, state):
		self.state.swicth(state)


if __name__ == "__main__":
	comp = Computer()
	comp.change(On)
	comp.change(Off)
	comp.change(On)
	comp.change(Suspend)
	comp.change(Hibernate)
	comp.change(On)
	comp.change(Off)

输出:

Current: off => switched to new state on
Current: on => switched to new state off
Current: off => switched to new state on
Current: on => switched to new state suspend
Current: suspend  => switching to hibernate not possible.
Current: suspend => switched to new state on
Current: on => switched to new state off

你可能感兴趣的:(python,python)