设计模式(python)

设计模式

1.设计模式与面向对象简绍

image-20250830082812385

image-20250830083126978

1.python 中接口实现的两种方式

image-20250830083311393

class A:
    def run(self, object1):
        pass

class B:
    def fun(self, object1):
        pass


p = A()
def total_run(p, object1):
    p.run(object1)
    
# 调用不同的类的 方法名相同,方法的参数相同, (限制接口的调用方式)
# 在父类中定义 抽象接口, 子类继承父类,子类必须以同样的函数名和参数实现父类的方法, 如果子类未定义,会抛出异常,
# 问题: 抛出异常的时刻在 调用对象方法的时候, 如果不调用 对象方法不报错

class Base:
    def run(self, object1):
        raise NotImplementedError

class A(Base):
    def run(self, object1):
        pass

class B(Base):
    def fun(self, object1):
        pass


p = A()
def total_run(p, object1):
    p.run(object1)

image-20250830084911958

image-20250830085124137

# 使用抽象类,抽象方法, 抽象类继承 ABCMeta 类, 抽象类中的方法使用 @abstractmethod 装饰器装饰
# 有抽象方法的类叫做抽象类, 抽象类不能实例化, 子类重写父类的方法, 那么子类中就没有抽象方法了(和 c++ 中的多态有点相似)就可以实例化了

from abc import ABCMeta, abstractmethod

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

class Alipay(Payment):
    # def pay(self, money):
    #     pass
    pass

class WecharPay(Payment):
    def pay(self, money):
        pass


p = Alipay()

image-20250830090215244

2.面向对象设计原则

image-20250830090945426

# 里氏替换原则
# 例如 下面两个类, 父类和子类应该返回相同的对象。父类和子类应该有相同的 调用方式(使用方式)
class User:
    def show_name(self):
        pass
    
    
class VIPUser(User):
    def show_name(self):
        pass
    
u = User()
res = u.show_name()
# 依赖倒置原则

"""
高层代码:在这里, 例如是一些需要调用 pay 方法的代码
底层代码: 每中 不同的 pay 方法的具体实现,例如 alipay,  wechatpay

定义一个抽象类, 底层代码继承 抽象类进行实现,具有统一的调用方式, 高层代码 依赖 抽象类, 而不依赖底层代码

抽象不依赖细节, 细节依赖抽象, : 先写接口,实现外在表现由接口限制(人话)
"""
from abc import ABCMeta, abstractmethod

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

class Alipay(Payment):
    # def pay(self, money):
    #     pass
    pass

class WechatPay(Payment):
    def pay(self, money):
        pass


p = Alipay()

image-20250830092728757

接口隔离原则,例如下图, tiger 类继承 animal 类,tiger(老虎) 只有走行为,如果继承总的接口 animal 类就需要实现一些 tiger 类本身不需要的方法, 例如 swim, fly , 设计不合理。

image-20250830093046805

# 接口隔离原则, 使用专门的接口, 而不使用单一的总接口

from abc import ABCMeta, abstractmethod

class landAnimal(metaclass=ABCMeta):
    @abstractmethod
    def walk(self):
        pass
    
class WaterAnimal(metaclass=ABCMeta):
    @abstractmethod
    def swim(self):
        pass
    
class SkyAnimal(metaclass=ABCMeta):
    @abstractmethod
    def fly(self):
        pass
    
class Tiger(landAnimal):
    def walk(self):
        print("Tiger is walking")
    
        

3.设计模式分类

image-20250830102343944

4.简单工程模式

image-20250830102546804

"""
一个抽象类, 一些具体实现继承 抽象类, 创建一个类 根据传递的参数的不同,调用不同的类,可以在调用类中设置一些默认的参数,通过工厂类(PaymentFactory)调用具体的 对象
"""

from abc import ABCMeta, abstractmethod

# 抽象产品角色
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass

# 具体产品角色
class Alipay(Payment):
    def pay(self, money):
        print("111")

# 具体产品角色
class WechatPay(Payment):
    def pay(self, money):
        pass

# 工厂角色
class PaymentFactory:
    def create_payment(self, method):
        if method == "alipay":
            return Alipay()
        elif method == "wechat":
            return WechatPay()
        else:
            raise TypeError("No such payment named %s" %(method))

# client
pf = PaymentFactory()
p = pf.create_payment("alipay")
p.pay(100000)

image-20250830103945107

5.工厂方法模式

image-20250830104059800

"""
工厂方法模式, 将工厂角色进行抽象, 不同的工厂角色有不同的实现
使用 抽象工厂角色和 具体工厂角色, 可以在工厂调用的工厂中 传递一些不需要上层代码传递的参数, 可以隐藏一些细节, 简化高层调用。
"""
from abc import ABCMeta, abstractmethod

# 抽象产品角色
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass

# 具体产品角色
class Alipay(Payment):
    def pay(self, money):
        print("111")

# 具体产品角色
class WechatPay(Payment):
    def pay(self, money):
        pass

# 抽象 工厂角色
class PaymentFactory(metaclass=ABCMeta):
    @abstractmethod
    def create_payment(self):
        pass

# 具体工厂角色
class AlipayFactory(PaymentFactory):
    def create_payment(self):
        return Alipay()

# 具体工厂角色
class WechatPayFactory(PaymentFactory):
    def create_payment(self):
        return WechatPay()


pf = AlipayFactory()
p = pf.create_payment()
p.pay(1000)

image-20250830105508191

6.抽象工厂模式

image-20250830105631684

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 BigShell(PhoneShell):
    def show_shell(self):
        print("普通手机大手机壳")


class AppleShell(PhoneShell):
    def show_shell(self):
        print("苹果手机壳")


class SnapDragonCPU(CPU):
    def show_cpu(self):
        print("晓龙CPU")


class MediaTekCPU(CPU):
    def show_cpu(self):
        print("联发科CPU")


class AppleCPU(CPU):
    def show_cpu(self):
        print("苹果CPU")


class Android(OS):
    def show_os(self):
        print("Android 系统")


class IOS(OS):
    def show_os(self):
        print("ios系统")


# ---- 具体工厂 -----
class MiFactory(PhoneFactory):
    def make_cpu(self):
        return SnapDragonCPU()

    def make_os(self):
        return Android()

    def make_shell(self):
        return BigShell()


# --- client ---

class Phone:
    def __init__(self, cpu, os, shell):
        self.cpu = cpu
        self.os = os
        self.shell = shell

    def show_info(self):
        print("phone message")
        self.cpu.show_cpu()
        self.os.show_os()
        self.shell.show_shell()


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


p1 = make_phone(MiFactory())
p1.show_info()

image-20250830112117547

image-20250830112139989

image-20250830112203981

7.建造者模式

image-20250830112706358

from abc import ABCMeta, abstractmethod


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)


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


class SexyGirlBuilder(PlayerBuilder):
    def __init__(self):
        self.player = Player()

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

    def build_body(self):
        self.player.body = "苗条"

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

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


class Monster(PlayerBuilder):
    def __init__(self):
        self.player = Player()

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

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

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

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


class PlayerDirector:

    def build_players(self, builder):
        #  控制对象的组装顺序
        builder.build_body()
        builder.build_face()
        builder.build_arm()
        builder.build_leg()
        return builder.player


# client

builder = SexyGirlBuilder()
director = PlayerDirector()
p = director.build_players(builder)
print(p)


builder = Monster()
director = PlayerDirector()
p = director.build_players(builder)
print(p)

image-20250830114848348

image-20250830115040401

8.单例模式

image-20250830115215754

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(20)
print(a.a)  # 20
print(b.a)  # 20

print(id(a))  # 2394949577296
print(id(b))  # 2394949577296

image-20250830120341066

9.适配器模式

image-20250830181342494

image-20250830181410808

"""
两个系统合并成一个新的系统, 支付方法中的方法名不一样,bankpay 中使用的 cost 方法,其他使用的是 pay 方法

底层支付代码在 高层代码中都有使用, 不能够直接的修改 方法名

可以使用 适配器
"""

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 WechatPayment(Payment):
    def pay(self, money):
        print("微信支付%d元" % money)


class BankPay:
    def cost(self, money):
        print("银联支付%d元" % money)


p = BankPay()
p.pay(100)

image-20250830182315831

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 WechatPayment(Payment):
    def pay(self, money):
        print("微信支付%d元" % money)


class BankPay:
    def cost(self, money):
        print("银联支付%d元" % money)

# 类适配器
# 适配器
class NewBankPay(Payment, BankPay):
    def pay(self, money):
        self.cost(money)


p = NewBankPay()
p.pay(100)
# 组合  在一个类中放入另一个类的对象
class A:
    pass


class B:
    def __init__(self):
        self.a = A()
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 WechatPayment(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 PaymentAdapter(Payment):
    def __init__(self, payment):
        self.payment = payment

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


p = PaymentAdapter(ApplePay())
p.pay(100)

p = PaymentAdapter(BankPay())
p.pay(100)

image-20250830184850818

10.桥模式

image-20250830185036215

"""
例如一个画图软件, 有 形状 和 颜色两个维度, 
可以使用如下方式实现, 3 个颜色, 3个形状, 两两组合需要 9个类, 不易扩展
"""
class Shape:
    pass


class Line(Shape):
    pass


class Rectangle(Shape):
    pass


class Circle(Shape):
    pass


class RedLine(Line):
    pass


class GreenLine(Line):
    pass


class BuleLine(Line):
    pass
# 桥接模式

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()


shape = Circle(Green())
shape.draw()

image-20250830191628475

image-20250830191807772

image-20250830191901311

11.组合模式

image-20250830192031925

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("----复合图形-----")


"""
一个线段由两个点组成, 写一个抽象的图像类, 一个点类, 一个线段类
线段由 两个点组成, 线段对象接收两个 点类的对象, 组合成 线段对象
"""
l = Line(Point(1, 1), Point(2, 2))
print(l)


p1 = Point(2, 3)
l1 = Line(Point(3, 4), Point(6, 7))
l2 = Line(Point(1, 5), Point(2, 8))
pic = Picture([p1, l1, l2])
pic.draw()

image-20250830194139884

image-20250830194335251

image-20250830194536392

12.外观模式

image-20250830194722561

# 子系统类
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("内存断电")


# 外观, facade
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()

image-20250830200045544

13.代理模式

image-20250830200149938

"""
一个抽象类, 一个真实的类, 在 初始化方法的时候,打开文件并读取内容, 调用 get_content 方法的时候,从类中获取数据,调用 set_content 方法的时候, 设置文件内容, 没有调用 get_content 的方法的时候, 文件内容就已经保存到类中了, 比较占内存, 使用代理模式 去调用 真实的类, 虚代理, 虚代理类在初始化的时候,不读取文件的内容
在调用 get_content 的时候,才 读取文件内容

通过增加一个新的类, 对已有的类进行 二次封装改造,达到 代理的作用。
"""
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
        print("读取文件内容")
        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):
        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 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("data.txt")

sub = VirtualProxy("data.txt")
print(subj.get_content())

subj = ProtectedProxy("data.txt")
print(subj.get_content())
subj.set_content("abc")

image-20250830214549078

13.责任链模式

image-20250830214719845

image-20250830214803691

"""
请假的例子, 请假天数小于等于 3天, 项目主管有权限 批准, 小于等于 5 天, 部门经理有权限批准
小于等于10天, 总经理有权限批准

写一个抽象处理者, 有三个 具体处理者, 项目经理类, 部门经理类, 总经理类,
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("总经理准假%d" % day)
        else:
            print(",,,,")

# 具体处理者
class DepartmetManager(Handler):
    def __init__(self):
        self.next = GeneralManager()

    def handle_leave(self, day):
        if day <= 5:
            print("部门经理准假%s天" % day)
        else:
            print("部门经理职权不足")
            self.next.handle_leave(day)

# 具体处理者
class ProjectDirector(Handler):
    def __init__(self):
        self.next = DepartmetManager()

    def handle_leave(self, day):
        if day <= 3:
            print("项目主管准假%d天" % day)
        else:
            print("项目主管职权不足")
            self.next.handle_leave(day)


# client
day = 11
h = ProjectDirector()
h.handle_leave(day)

image-20250830220916516

14.观察者模式

image-20250830221031824

image-20250830221142661

from abc import ABCMeta, abstractmethod


class Observer(metaclass=ABCMeta):   # 抽象订阅者
    @abstractmethod
    def update(self, notice):   # notice 是一个 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:
            obs.update(self)


class StaffNotice(Notice):  # 具体发布者
    def __init__(self, company_info=None):
        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


notice = StaffNotice("初始公司信息")
s1 = Staff()
s2 = Staff()
notice.attach(s1)
notice.attach(s2)
notice.company_info = "发奖金 !!!"
print(s1.company_info)
print(s2.company_info)
notice.detach(s2)
notice.company_info = "不发奖金 !!!"
print(s1.company_info)
print(s2.company_info)

image-20250831000913749

15.策略模式

image-20250831001044075

"""
定义一个抽象策略接口 , 定义两个具体策略类, 定义一个上下文, 来设置不同的策略类
比如,打车时, 平台 匹配用户和 车辆的策略
"""
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)


# Client
data = "[....]"
s = FastStrategy()
s1 = SlowStrategy()
context = Context(s, data)
context.do_strategy()
context.set_strategy(s1)
context.do_strategy()

image-20250831002630217

16.模版方法模式

image-20250831002735201

from abc import ABCMeta, abstractmethod
from time import sleep


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()
                sleep(1)
            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)


MyWindow("hello").run()

image-20250831003856361

17.总结

image-20250831004009945

通过一些特别的场景的例子,来了解设计模式的使用方法,学习设计思想。

posted @ 2025-08-31 00:48  Ref-brief  阅读(11)  评论(6)    收藏  举报