【常用设计模式】待补充

news2024/11/24 12:30:18

Github仓库地址

概述

23中设计模型分为常见的三大类:创建型模式、结构型模式和行为型模式

image-20230605140632440

创建型模式

简单工厂模式

描述

简单工厂模式不是23中设计模式中的。简单工厂模式不直接向客户端暴露对象创建的细节,而是通过一个工厂类来负责创建产品类的实例

角色

  1. 抽象产品角色:给具体产品角色提供接口规范
  2. 具体产品角色:实现同类内容的不同实现结果
  3. 工厂角色:负责传入不同的参数,调用不同的具体产品角色,实现不同的功能

实现

from abc import ABCMeta, abstractmethod

# 抽象产品角色:给具体产品角色提供统一的接口规范
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass
# 具体产品角色
class Alipay(Payment):
    def __init__(self, use_huabei=False):
        self.use_huabei = use_huabei

    def pay(self, money):
        if self.use_huabei == True:
            print("花呗支付了{0}元!".format(money))
        else:
            print("支付宝余额支付了{0}元!".format(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 == 'WechatPay':
            return WechatPay()
        elif method == 'HuabeiPay':
            return Alipay(use_huabei=True)
        else:
            raise TypeError('No such payment named %s' % method)

优点

  1. 隐藏了对象(具体产品角色)创建的细节
  2. 面对新的具体产品对象,客户端(上层)不需要修改代码,仅在参数传递上有所改动

缺点

  1. 违反了单一职责原则:工厂类对象中包含了多种具体产品角色的选择逻辑
  2. 违反了开放封闭原则:当新增具体产品角色时,需要对工厂类对象进行修改

工厂方法模式

描述

在简单工厂模式的基础上,定义一个抽象工厂和具体工厂的角色,从而让客户端决定具体实例化哪一个产品

角色

  1. 抽象产品角色:给具体产品角色的创建提供接口规范
  2. 具体产品角色:创建不同的产品
  3. 抽象工厂角色:给具体产品角色的调用提供接口规范
  4. 具体工厂角色:创建不同的工厂

实现

from abc import ABCMeta, abstractmethod

# 抽象产品角色:给具体产品角色提供统一的接口规范
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass
# 具体产品角色
class Alipay(Payment):
    def __init__(self, use_huabei=False):
        self.use_huabei = use_huabei

    def pay(self, money):
        if self.use_huabei == True:
            print("花呗支付了{0}元!".format(money))
        else:
            print("支付宝余额支付了{0}元!".format(money))
            
class WechatPay(Payment):
    def pay(self, money):
        print("微信支付了%d元!" % (money))
# 抽象工厂角色
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 Alipay()

class HuabeiFactory(PaymentFactory):
    def create_payment(self):
        return Alipay(use_huabei=True)
# 客户端调用
hfp = HuabeiFactory().create_payment()
hfp.pay(100)

优点

  1. 每个具体产品一一对应一个具体工厂类,不需要修改具体工厂类代码
  2. 隐藏具体产品对象创建的实现细节

缺点

  1. 每增加一个具体产品类,需要增加一个相应的具体工厂类

抽象工厂模式

描述

在工厂模式的基础上又进行了一层抽象提取

角色

  1. 抽象产品角色:给具体产品角色的创建提供接口规范
  2. 具体产品角色:创建不同的产品
  3. 抽象工厂角色:给具体产品角色的调用提供接口规范
  4. 具体工厂角色:创建不同的工厂
  5. 客户端

实现

from abc import ABCMeta, abstractmethod

# 抽象产品角色
class PhoneShell(metaclass=ABCMeta):
    @abstractmethod
    def show_shell(self):
        pass

class PhoneCPU(metaclass=ABCMeta):
    @abstractmethod
    def show_cpu(self):
        pass

class PhoneOS(metaclass=ABCMeta):
    @abstractmethod
    def show_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(PhoneCPU):
    def show_cpu(self):
        print('骁龙CPU')

class HuaweiCPU(PhoneCPU):
    def show_cpu(self):
        print('化为CPU')

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

class AndroidOS(PhoneOS):
    def show_os(self):
        print('IOS系统')

class AppleOS(PhoneOS):
    def show_os(self):
        print('安卓系统')
# 抽象工厂角色
class PhoneFactory(metaclass=ABCMeta):
    @abstractmethod
    def make_shell(self):
        pass

    @abstractmethod
    def make_cpu(self):
        pass

    @abstractmethod
    def make_os(self):
        pass
# 具体工厂角色
class HuaweiFactory(PhoneFactory):
    def make_shell(self):
        return SmallShell()

    def make_cpu(self):
        return HuaweiCPU()

    def make_os(self):
        return AndroidOS()

# 对具体工厂的实现加以限制,避免随意使用:苹果手机只能用苹果的CPU
class AppleFactory(PhoneFactory):
    def make_shell(self):
        return AppleShell()

    def make_cpu(self):
        return AppleCPU()

    def make_os(self):
        return AppleOS()
# 客户端
class Phone:
    def __init__(self, shell, cpu, os):
        self.shell = shell
        self.cpu = cpu
        self.os = os

    def show_info(self):
        print('手机信息:')
        self.shell.show_shell()
        self.cpu.show_cpu()
        self.os.show_os()


def make_phone(factory):
    shell = factory.make_shell()
    cpu = factory.make_cpu()
    os = factory.make_os()
    return Phone(shell, cpu, os)
# 用户端调用
p = make_phone(HuaweiFactory())
p.show_info()

优点

  1. 客户端与类的具体实现相分离
  2. 每个工厂都能创建一个完整的产品系列
  3. 产品之间存在约束关系:有利于产品的一致性

缺点

  1. 难以支持新种类的(抽象)产品:例如要增加内存版本的生产信息(抽象产品需要新增),则所有的工厂都需要修改(抽象工厂需要修改)

建造者模式

描述

将一个复杂对象的构建与他的表示分离,是的同样的构建过程可以创建不同的表示

角色

  1. 产品
  2. 抽象创建者
  3. 具体创建者
  4. 指挥者

实现

from abc import ABCMeta, abstractmethod

# 产品
class Player_Product:
    def __init__(self, face=None, body=None, arms=None, legs=None):
        self.face = face
        self.body = body
        self.arms = arms
        self.legs = legs

    def __str__(self):
        return '%s,%s,%s,%s' % (self.face, self.body, self.arms, self.legs)
# 抽象建造者
class PlayerBuilder(metaclass=ABCMeta):
    @abstractmethod
    def build_face(self):
        pass

    @abstractmethod
    def build_body(self):
        pass

    @abstractmethod
    def build_arms(self):
        pass

    @abstractmethod
    def build_legs(self):
        pass
# 具体建造者,隐藏了一个产品的内部结构
class GirlBuilder(PlayerBuilder):
    def __init__(self):
        self.player = Player_Product()

    def build_face(self):
        self.player.face = '漂亮的脸蛋'

    def build_body(self):
        self.player.body = '苗条的身材'

    def build_arms(self):
        self.player.arms = '细细的胳膊'

    def build_legs(self):
        self.player.legs = '大长腿'


class MonsterBuilder(PlayerBuilder):
    def __init__(self):
        self.player = Player_Product()

    def build_face(self):
        self.player.face = '绿脸'

    def build_body(self):
        self.player.body = '魁梧的身体'

    def build_arms(self):
        self.player.arms = '粗壮的胳膊'

    def build_legs(self):
        self.player.legs = '粗壮的大腿'
# 指挥者,构造代码(构造代码和表示代码分开),可以对构造过程进行更加精细地控制
class PlayerDirectory():
    def builder_player(self, builder):
        """
        隐藏了装配过程
        :param builder:
        :return:
        """
        builder.build_face()
        builder.build_body()
        builder.build_arms()
        builder.build_legs()
        return builder.player
# 用户端调用
builder = GirlBuilder()
director = PlayerDirectory()
p = director.builder_player(builder)
print(p)

优点

  1. 具体建造者之间独立,容易扩展
  2. 便于控制细节风险

缺点

  1. 产品需要有共同点,这些共同点通过不同的组合可以组合出不同的产品
  2. 如果这些共同点可以组成极多的产品,则会有很多的产品建造者

抽象工厂 VS 建造者模式

  1. 前者注重整体:每一个具体工厂都能制造一个产品:华为手机工厂、苹果手机工厂、锤子手机工厂
  2. 后者注重局部:产线就一个(指挥者),根据搭配(具体建造者)制造不同的产品:用ardroid、麒麟、小手机壳,就生产华为手机;用ios、M2、大手机壳,就生产苹果手机

理解

https://zhuanlan.zhihu.com/p/405399335

这个描述绝了

抽象工厂模式像是从某宝输入“电脑”的关键字直接进行购买,获得一个已经完整的电脑。

创建者模式,更像是“找个一个电脑的外壳,往该外壳内一步一步的组装零件,最后得到一个完整的电脑”。

单例模式

描述

保证一个类只有一个实例,并提供一个访问它的全局访问点

角色

  1. 单例

实现

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
# 用户端调用
ms1 = MyClass(1)
ms2 = MyClass(2)
print(ms1.a, ms2.a)
print(id(ms1), id(ms2))

优点

  1. 对唯一实例的受控访问
  2. 单例相当于全局变量,防止了命名空间被污染

结构型模式

适配器模式

描述

将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作

角色

  1. 目标接口
  2. 待适配的类
  3. 适配器

实现1:多继承

from abc import ABCMeta, abstractmethod

# 目标接口:抽象方法
class Payment(object, metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass

# 目标接口:具体实现
class Alipay(Payment):
    def pay(self, money):
        print('支付了%d' % money)
# 待适配的类
class BankPay():
    def cost(self, money):
        print('银联支付了%d' % money)
# 类适配器
class PaymentAdapter(Payment, BankPay):
    """
    把不兼容cost转换成pay
    """

    def pay(self, money):
        self.cost(money)
# 客户端调用
p = PaymentAdapter()
p.pay(100)

优点

  1. 想使用一个已经存在地类,而它的接口不符合要求
  2. 适用于单个对象需要适配的场景:多继承的适配方式,一个类适配器只能适配一个待适配的类

实现2:组合

from abc import ABCMeta, abstractmethod

# 目标接口:抽象方法
class Payment(object, metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass

# 目标接口:具体实现
class Alipay(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)

优点

  1. 想使用多个已经存在地类,而他们的接口不符合要求,但他们的接口都一致
  2. 适用于多个对象需要适配的场景:组合的适配方式,一个类适配器可以适配多个接口一致的待适配的类

桥模式

有难度,暂时跳过

https://blog.csdn.net/hbuxiaofei/article/details/106888178

组合模式

外观模式

代理模式

行为型模式

责任链模式

观察者模式

策略模式

模板方法模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/613824.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

12.MSP432E4 Keil烧录报错Error Flash Download failed - Cortex-M4

一、简介 前段时间琢磨了一块新板子,ESP432E401Y。 遇到一个问题,简单记录一下,问题是在keil中正常烧录程序后,在CCS下也烧录了一次程序,然后就一直无法再到keil中烧录,但是CCS一直是正常烧录的。keil报错…

Spark集群搭建

系列文章目录 Ubuntu常见基本问题 Hadoop3.1.3安装(单机、伪分布) Hadoop集群搭建 HBase2.2.2安装(单机、伪分布) Zookeeper集群搭建 HBase集群搭建 Spark安装和编程实践(Spark2.4.0) Spark集群搭建 文章目…

linux开发:linux最大线程数分析

linux最大线程数分为,进程最大线程数,用户最大进程数, 整个系统已用的线程或进程数。 我们可以用下面命令进行查询这三个进程数。 linux系统可生成最大线程数可以用这个命令查询 cat /proc/sys/kernel/threads-max 进程最大线程数查询方式 ps…

家用儿童帆布床出口欧盟CE认证EN716测试

1.标准适用范围 该标准规定了内部长度大于900mm但不超过1400mm的家用童床的安全要求。该安全要求适用于完全组装完毕待用的童床。可以转换成其它产品的童床(如:可变产品、游戏床)转换后应该符合相关欧洲标准。该标准不适用于提篮、婴儿床和摇…

hacknet攻略(更新中)

序章 然后点自己的电脑,再点一下SCAN(扫描可用主机),再点断开 然后点蓝色的电脑,是连接的意思 点中间Probe系统图标,看开放端口数 若端口数为0可以使用porthakc命令直接黑入系统 几个会用到的命令cd, rm * ,dc关闭连接&…

Unity制作二次元卡通渲染角色材质——4 、内外描边和细节添加

Unity制作二次元材质角色 回到目录 大家好,我是阿赵。 这里继续讲二次元角色材质。这次打算讲一下描边和细节的添加。 一、外描边 外描边的做法也不止一种,比如后处理方法的偏导数ddx/ddy之类的,也能整个屏幕的求出边缘。但一般来说单模型渲…

MySQL数据库学习笔记(九)实验课六之触发器和存储过程

没想到这就是最后一次实验了。 一点知识: 道具 – delimiter / DELIMITER 这是用于指定语句分隔符的特殊命令 默认情况下,MySQL使用分号(;)作为语句的结束符。然而,当我们需要定义存储过程、触发器或函数等包含多条S…

51智能小车-串口控制、循迹、避障

目录 1.串口控制小车 2.循迹小车 3.避障小车 1.串口控制小车 L9110s概述 接通VCC,GND 模块电源指示灯亮, 以下资料来源官方,但是不对,根据下节课实际调试 IA1输入高电平,IA1输入低电平,【OA1 OB1】电机…

总结890

学习目标: 月目标:6月(线性代数强化9讲2遍,背诵15篇短文,考研核心词过三遍) 周目标:线性代数强化3讲,英语背3篇文章并回诵,检测 每日必复习(5分钟&#xff…

STM32开发——简介、开发环境(Keil5、CubeMX)、HAL库

目录 1.简介-初识STM32 2.开发环境 2.1使用Keil5 2.2使用STM32CubeMX 3.标准库与HAL库区别 4.推挽输出与开漏输出 1.简介-初识STM32 什么是单片机? 单片机(Single-Chip Microcomputer)是一种集成电路芯片,把具有数据处理能…

kafka部分面试常见问题及其解答(接上)

16. kafka创建Topic时如何将分区分配给各Broker 副本因子不能大于 Broker 的个数;第1个分区(partition_0)的第1个副本放置位置是随机从brokerList选择的;其他分区的第一个副本放置位置相对于partition_0依次往后移。 如果我们有5…

vue 3 第三十二章:状态管理(Pinia状态持久化)

Pinia 的状态持久化 在实际开发中,我们通常需要对状态进行持久化或缓存,以便在应用程序重新加载或离线时仍然能够访问数据。在 Pinia 中,我们可以使用插件来实现状态的持久化和数据缓存。 Pinia 提供了一个名为pinia-plugin-persist的插件&…

Linux - 文件操作和系统接口

​​​​​​​ 感谢各位 点赞 收藏 评论 三连支持 本文章收录于专栏【Linux系统编程】 ❀希望能对大家有所帮助❀ 本文章由 风君子吖 原创 ​​​​​​​ ​​​​​​​ ​​​​​​​ ​ 前言 对于文件操作,不知大家是否有过接…

永恒之黑漏洞复现

一、实验环境搭建 系统镜像: ed2k://|file|cn_windows_10_consumer_editions_version_1903_x64_dvd_8f05241d.iso|4905476096|F28FDC23DA34D55BA466BFD6E91DD311|/ 建议使用迅雷下载,安装版本选win10专业版 安装完后记得一定要关闭defender,防火墙&…

配置主机加入已有 tinc 集群简明过程

文章目录 Cent OS服务器安装tinc配置文件过程中使用到的一些Linux命令小记 启动tinc开放端口 Windows主机参考资料 本文的主要内容是如何将主机加入已有的 tinc 集群。 Cent OS服务器 安装tinc yum install tinc如果不先 su 到 root 账户的话,可能会无法安装。 因…

Python模块os 操作系统

目录 1. 系统类 --------------------- 解释器 --------------------- system 执行系统命令 wait 等待任意子进程 waitpid 等待指定的子进程 kill 指定杀死进程 abort 立即中止解释器 pipe 管道操作 --------------------- 随机字符 --------------------- urandom …

KMeans+DBSCAN密度聚类+层次聚类的使用(附案例实战)

🤵‍♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞&#x1f4…

数据结构之栈、队列——算法与数据结构入门笔记(四)

本文是算法与数据结构的学习笔记第四篇,将持续更新,欢迎小伙伴们阅读学习 。有不懂的或错误的地方,欢迎交流 栈 栈是一种线性数据结构,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶 (Top&…

虚幻5-编辑器扩展开发Editor-Slate的TabManager结构如下

目录 Editor-Slate WorkSpaceMenu(Slate相关类) Editor-Tab-界面刷新 Editor-Slate 基本上,地球人都知道(我不是地球人)虚幻引擎的Editor界面(自定义)通过Slate管理 Slate的入口是方法::Co…

检测到“_CRT_STDIO_ISO_WIDE_SPECIFIERS”的不匹配项

libboost_thread-vc142-mt-x64-1_82.lib(thread.obj) : error LNK2038: 检测到“_CRT_STDIO_ISO_WIDE_SPECIFIERS”的不匹配项: 值“0”不匹配值“1”(AcadStr.obj 中) 1> 正在创建库 x64\Release\ArxDbg.lib 和对象 x64\Release\ArxDbg.exp : fatal error LNK1319: 检测到 …