python - 编程中【工厂模式】和【单例模式】区别以及代码示例详解

news2024/12/28 5:22:54

一. 概念

工厂模式和单例模式都是面向对象编程中常用的设计模式。

  1. 工厂模式(FactoryPattern):是一种创建型模式,它提供了一种方法来创建对象,而不需要暴露对象的创建逻辑。这种模式通过定义一个工厂类,通过工厂方法来创建对象。工厂模式可以将对象的创建过程独立到一个单独的工厂类中,从而实现解耦,降低系统的耦合性,并提高系统的可扩展性和可维护性。工厂模式包括简单工厂模式、工厂方法模式和抽象工厂模式等。
  2. 单例模式(Singleton Pattern):是一种创建型模式,它保证一个类只有一个实例,并提供一个全局访问点,让外界能够访问到这个实例。单例模式可以避免系统中出现过多的重复对象,从而提高系统的性能和效率。确保一个类只有一个实例存在,从而实现对象的共享和控制对象的创建,同时可以提高系统性能。

二. 区别

  1. 目的不同:工厂模式的主要目的是将对象的创建过程独立到一个单独的工厂类中,从而实现解耦,降低系统的耦合性,并提高系统的可扩展性和可维护性;而单例模式的主要目的是确保一个类只有一个实例存在,从而实现对象的共享和控制对象的创建。

  2. 返回值不同:工厂模式通常会返回一个新的对象实例,而单例模式则会返回同一个实例。

  3. 实现方式不同:工厂模式通常会定义一个工厂类,用于创建对象,可以根据不同的参数值来创建不同的对象实例;而单例模式则需要在类中定义一个静态成员对象,通过调用类的静态方法来获取这个对象实例。

三. 示例代码

1. 工厂模式

示例代码

class Car:
    def __init__(self, brand):
        self.brand = brand

    def run(self):
        print(f'{self.brand} car is running')


class CarFactory:
    def create(self, brand):
        return Car(brand)


car_factory = CarFactory()
car1 = car_factory.create('BMW')
car1.run()
car2 = car_factory.create('Benz')
car2.run()
print(car1 is car2)

运行结果

在这里插入图片描述

可以看到以上运行的结果,实例对象传进去的参数输出都是独立的,并且对象也都是不一样的。

2. 单例模式

示例代码

在类的内部,定义了一个实例变量 __instance,并重写了 __new__ 方法来控制实例的创建。在实例化该类的时候,如果实例对象不存在,则创建该实例对象,否则直接返回实例对象。

class Singleton:
    __instance = None

    def __new__(cls):
        if not cls.__instance:
            cls.__instance = super().__new__(cls)
        return cls.__instance

    def __init__(self):
        self.at = False

    def set_at(self, a):
        if a:
            self.at = True
        else:
            self.at = False


if __name__ == '__main__':
    s1 = Singleton()
    s2 = Singleton()

    print('s1 is s2 --->', s1 == s2)  # True
    s1.set_at(0)
    print('set s1 at -->', s1.at)
    print('s2 at ------>', s2.at)
    s2.set_at(1)
    print('set s2 at -->', s2.at)
    print('=====================')
    print('s1 at -->', s1.at)
    print('s2 at -->', s2.at)

运行结果

在这里插入图片描述
从以上运行结果我们可以看到,两个实列s1和s2创建之后是指向同一个对象的,在设置属性时也是以最后的实例设置的结果为准,这样就可以实现数据的同步与共享了。

四. 附上其他单例模式几种写法

1. 使用模块方式实现单例模式

Python中加载模块时会缓存,所以在导入一个模块时,不管导入多少次,都只会创建一个实例。

# singleton.py
class Singleton:
    def __init__(self):
        pass

singleton = Singleton()

# main.py
from singleton import singleton

s1 = singleton
s2 = singleton
print(s1 is s2)  # 输出 True

2. 使用装饰器实现单例模式

def singleton(cls):
    instances = {}

    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return get_instance

@singleton
class MyClass:
    pass

3. 使用元类实现单例模式

元类是Python中比较高级的概念,我们可以通过定义一个元类,并在该元类的__call__()方法中判断类是否已经被实例化,从而实现单例模式。

class SingletonMeta(type):

    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]

class MyClass(metaclass=SingletonMeta):
    pass

s1 = MyClass()
s2 = MyClass()

print(s1 == s2)   # 输出True

在上面的代码中,我们创建了一个元类 SingletonMeta,它继承自 type 类,同时重写了 __call__ 方法。__call__ 方法在创建实例的时候被调用,我们重写了该方法来控制实例的创建。在实例化 Singleton 的时候,会自动调用元类中的 __call__ 方法,创建实例对象。

五. 总结

工厂模式和单例模式是两种不同的设计模式,它们的目的和实现方式都有所不同。工厂模式主要用于对象的创建,单例模式则主要用于对象的共享。在实际应用中,我们可以根据具体的需求和场景进行选择。

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

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

相关文章

优化生产流程:数字化工厂中的OPC UA分布式IO模块应用

背景 近年来,为了提升在全球范围内的竞争力,制造企业希望自己工厂的机器之间协同性更强,自动化设备采集到的数据能够发挥更大的价值,越来越多的传统型工业制造企业开始加入数字化工厂建设的行列,实现智能制造。 数字化…

归一化的作用,sklearn 安装

目录 归一化的作用: 应用场景说明 sklearn 准备工作 sklearn 安装 sklearn 上手 线性回归实战 归一化的作用: 归一化后加快了梯度下降求最优解的速度; 归一化有可能提高精度(如KNN) 应用场景说明 1)概率模型不需要归一化&#xff…

强化历程5-Java并发系列(2023.8.23)

文章目录 强化历程5-Java并发系列(2023.8.23)1 Java多线程1.1 Java中多线程有几种实现方式?1.2 那么Runnable和Callable都可以实现多线程,他们有什么区别?1.3 采用实现Runnable和Callable接口方式和采用继承Thread类方式各有什么好处?1.4 Java如何停止…

【数据结构与算法】—— 手撕红黑树

目录 (一)红黑树的定义 1、红黑树的引入 2、红黑树的概念 3、红黑树的性质 (二)红黑树的操作 1、红黑树节点的定义 2、红黑树的插入操作 1️⃣ 思路 2️⃣ 代码实现 3、红黑树的删除操作(了解) …

Compose - 基本使用

一、概念 1.1 Compose优势 由一个个可以组合的Composable函数拼成界面,方便维护和复用。布局模型不允许多次测量,提升了性能。Compose可以和View互操作(相互包含对方)。 1.2 声明式UI APP展示的数据绝大多数不是静态数据而是会…

An easy problem

一、题目 we define f(A) 1, f(a) -1, f(B) 2, f(b) -2, … f(Z) 26, f(z) -26; Give you a letter x and a number y , you should output the result of yf(x). Input On the first line, contains a number T.then T lines follow, each line is a case.each case …

多线程基础篇(包教包会)

文章目录 一、第一个多线程程序1.Jconsole观察线程2.线程休眠-sleep 二、创建线程三、Thread类及常见方法1. Thread 的常见构造方法2. Thread 的几个常见属性3. 启动线程 - start4. 中断线程5. 等待一个线程 四、线程状态五、线程安全问题(synchronized)(重点&#…

基于React实现日历组件详细教程

前言 日历组件是常见的日期时间相关的组件,围绕日历组件设计师做出过各种尝试,展示的形式也是五花八门。但是对于前端开发者来讲,主要我们能够掌握核心思路,不管多么奇葩的设计我们都能够把它做出来。 本文将详细分析如何渲染一…

windows系统activemq一键安装启动

前言 官网下载的mq提供了启动和卸载服务器的脚本,但是安装的时候不会自动启动服务,需要去手动比较麻烦,执行脚本的时候也需要去右键选择管理员执行做起来比较啰嗦。 优化方案 修改脚本权限为自动判断并获取 在脚本开头加入下面的代码 …

店铺收款系统开源_商城收款分账系统_OctShop

近来,很多客户对OctShop店铺收款分账系统有很大的需求,下面详细介绍一下,门店收款分账系统是什么,以及其作用与意义是什么? 店铺收款分账系统实质上是一个解决门店各种收款场景,如:扫码付款&…

零基础学习,初学者也能轻松制作高质量母婴行业小程序

现如今,随着移动互联网的发展,小程序成为了各行各业的新宠。对于母婴行业来说,拥有一个功能完善、用户友好的小程序,无疑是提升企业形象和服务质量的重要一环。然而,对于初学者来说,如何轻松掌握母婴行业小…

微服务中间件--http客户端Feign

http客户端Feign http客户端Feigna.Feign替代RestTemplateb.自定义Feign的配置c.Feign的性能优化d.Feign的最佳实践分析e.Feign实现最佳实践(方式二) http客户端Feign a.Feign替代RestTemplate 以前利用RestTemplate发起远程调用的代码: String url "http:…

【面试题】你理解中JS难理解的基本概念是什么?

前端面试题库 (面试必备) 推荐:★★★★★ 地址:前端面试题库 作用域与闭包 作用域 作用域是当前的执行上下文,值和表达式在其中“可见”或可被访问。如果一个变量或表达式不在当前的作用域中&#xff0…

SpringBoot利用ConstraintValidator实现自定义注解校验

一、前言 ConstraintValidator是Java Bean Validation(JSR-303)规范中的一个接口,用于实现自定义校验注解的校验逻辑。ConstraintValidator定义了两个泛型参数,分别是注解类型和被校验的值类型。在实现ConstraintValidator接口时&…

【业务功能篇77】微服务-OSS对象存储-上传下载图片

3. 图片管理 文件存储的几种方式 单体架构可以直接把图片存储在服务器中 但是在分布式环境下面直接存储在WEB服务器中的方式就不可取了,这时我们需要搭建独立的文件存储服务器。 3.1 开通阿里云服务 针对本系统中的相关的文件,图片,文本等…

JavaSE 数组

定义: int []arr; int arr[]; 初始化 // 完整格式 int arr[] new int[]{1, 2, 3}; // 简单格式 int arr[] {1, 2, 3}; 数组的元素访问、遍历 按照下标访问即可。数组的长度函数为 arr.length()。idea快速生成遍历的方法:数组名.fori 静态初始化 &a…

9.Sentinel哨兵

1.Sentinel Sentinel(哨兵)是由阿里开源的一款流量控制和熔断降级框架,用于保护分布式系统中的应用免受流量涌入、超载和故障的影响。它可以作为微服务架构中的一部分,用于保护服务不被异常流量冲垮,从而提高系统的稳定…

【神州数码】BGP路由器案例

SwitchB、SwitchC和SwitchD位于AS200中,SwitchA位于AS100中。SwitchA和SwitchB共享一个相同的网络段11.0.0.0。而SwitchB和SwitchD彼此物理上不相邻。 则SwitchA的配置如下: SwitchA(config)#router bgp 100SwitchA(config-router-bgp)#neighbor 11.1.1…

指针(初阶)

1. 指针是什么? 指针是什么? 指针理解的2个要点: 1. 指针是内存中一个最小单元的编号,也就是地址 2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量 总结:指针就是地址&…

Wlan——锐捷零漫游网络解决方案以及相关配置

目录 零漫游介绍 一代零漫游 二代单频率零漫游 二代双频率零漫游 锐捷零漫游方案总结 锐捷零漫游方案的配置 配置无线信号的信道 开启关闭5G零漫游 查看配置 零漫游介绍 普通的漫游和零漫游的区别 普通漫游 漫游是由一个AP到另一个AP或者一个射频卡到另一个射频卡的漫…