C++/python之设计模式(1)之什么是单例模式

news/2024/10/19 15:39:46/

python1_0">C++/python设计模式(1)之什么是单例模式

注:整理一些突然学到的C++、python知识,随时mark一下
例如:忘记的关键字用法,新关键字,新数据结构


设计模式整理

  • C++/python设计模式(1)之什么是单例模式
  • 一、 单例模式
    • 1、C++单例模式例子
    • 2、python单例模式例子
  • 总结


提示:本文为 C++、python 中单例模式的写法和举例


一、 单例模式

  单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类仅有一个实例,并提供一个全局性的访问点来获取该实例。单例模式在多种场景中都很有用,例如配置信息的读取、日志记录、线程池管理、数据库连接池等,这些场景通常只需要一个全局唯一的对象来执行特定的任务。

要实现单例模式,通常需要遵循以下步骤:

将构造函数私有化:通过将构造函数设为私有,可以阻止类的外部代码通过new关键字创建该类的实例。

在类内部创建静态实例:由于构造函数是私有的,类的外部无法创建实例,因此需要在类内部创建一个静态的实例。这个实例会在类首次被加载到内存时创建。

提供公共的静态方法获取实例:为了从类的外部获取这个唯一的实例,需要提供一个公共的静态方法,如getInstance(),用于返回这个静态实例。

禁止拷贝:为了防止通过拷贝构造函数和拷贝赋值操作符创建额外的实例,通常将它们设为私有或者禁用(使用= delete)。

1、C++单例模式例子

下面是一个简单的单例模式的C++实现示例:

cpp

#include <iostream>  
#include <memory>  class Singleton {  
private:  // 私有构造函数,防止外部创建实例  Singleton() {  std::cout << "Singleton instance created." << std::endl;  }  // 禁用拷贝构造函数  Singleton(const Singleton&) = delete;  // 禁用拷贝赋值操作符  Singleton& operator=(const Singleton&) = delete;  // 静态成员变量,保存唯一实例  static std::unique_ptr<Singleton> instance;  public:  // 静态方法,返回唯一实例  static Singleton* getInstance() {  if (!instance) {  instance.reset(new Singleton());  }  return instance.get();  }  // 其他成员函数...  void doSomething() {  std::cout << "Singleton doing something." << std::endl;  }  
};  // 类外初始化静态成员变量  
std::unique_ptr<Singleton> Singleton::instance = nullptr;  int main() {  Singleton* singleton1 = Singleton::getInstance();  Singleton* singleton2 = Singleton::getInstance();  // 检查是否指向同一个实例  if (singleton1 == singleton2) {  std::cout << "singleton1 and singleton2 are the same instance." << std::endl;  }  singleton1->doSomething();  return 0;  
}

在这个例子中,Singleton类通过以下方式确保单例行为:

构造函数是私有的,因此外部代码无法创建Singleton的实例。
静态成员变量instance是一个std::unique_ptr,它负责在程序结束时自动删除Singleton的唯一实例
getInstance()方法检查instance是否为空,如果是,则创建一个新的Singleton实例并返回其指针。由于instance是静态的,它只会被初始化一次,从而确保只有一个实例被创建。
拷贝构造函数和拷贝赋值操作符被禁用,防止了额外的实例被创建。
这个实现也考虑到了线程安全,因为在多线程环境下,可能会有多个线程同时调用getInstance()方法,从而导致创建多个实例。为了确保线程安全,通常需要使用互斥锁或其他同步机制来保护对instance的访问。在上面的示例中,由于使用了std::unique_ptr,在C++11及以后的版本中,其初始化是线程安全的,但getInstance()方法中的条件判断(如果实例为空则创建)并不是线程安全的,实际使用时需要添加适当的同步机制。

python_99">2、python单例模式例子

在Python中实现单例模式通常不需要像C++那样显式地控制构造函数和拷贝操作。Python提供了更简洁的方法来实现这一模式。下面是一个简单的Python单例模式的实现:

python

python">class Singleton:  _instance = None  def __new__(cls):  if not cls._instance:  cls._instance = super(Singleton, cls).__new__(cls)  return cls._instance  def do_something(self):  print("Singleton is doing something.")  # 使用单例  
singleton1 = Singleton()  
singleton2 = Singleton()  # 检查是否指向同一个实例  
if singleton1 is singleton2:  print("singleton1 and singleton2 are the same instance.")  singleton1.do_something()

在Python中,我们使用__new__方法而不是__init__方法来控制实例的创建。__new__方法在__init__之前被调用,用于创建并返回实例对象。在上面的代码中,_instance是一个类变量,它保存了单例的唯一实例。在__new__方法中,我们检查_instance是否为None,如果是,则调用父类的__new__方法创建一个新的实例并将其赋值给_instance。随后,我们总是返回_instance,确保无论多少次调用Singleton(),都返回同一个实例。

请注意,Python的单例实现不需要显式地禁止拷贝,因为Python中的对象是通过引用传递的,而不是通过值传递。因此,赋值操作实际上只是复制引用,而不是复制对象本身。此外,Python也没有像C++那样的拷贝构造函数和拷贝赋值操作符需要特别处理。

另外,如果你需要线程安全的单例,Python的__new__方法通常也已经是线程安全的,因为在CPython解释器中,全局解释器锁(GIL)确保了同一时间只有一个线程可以执行Python字节码。然而,如果你使用的是多进程环境或者对性能有严格要求的场景,可能需要使用更复杂的线程同步机制。在大多数情况下,简单的单例实现就已经足够了。

在Python中,super()函数用于调用父类(超类)的一个方法。当子类需要重写父类的方法,但又想保留父类的一些功能时,可以使用super()来调用父类的方法。在单例模式的上下文中,使用super()是为了确保当我们创建单例类的实例时,仍然按照正常的对象创建流程调用父类(即object类,因为所有Python类最终都继承自object)的__new__方法。

super(Singleton, cls).new(cls)做了以下几件事情:

super(Singleton, cls)返回一个临时对象,这个对象绑定到Singleton类的父类(在这种情况下是object类),并接收Singleton类作为第一个参数和当前类(由cls变量表示)作为第二个参数。

.new(cls)调用object类的__new__方法,并传入当前类(cls)作为参数。这实际上是请求Python为cls类创建一个新的实例。

在单例模式中,使用super()的目的是确保Singleton类的新实例是通过正常的Python对象创建机制来创建的,然后再通过我们的单例逻辑(即检查_instance是否为None)来确保我们不会意外地创建多个实例。

总结


http://www.ppmy.cn/news/1438413.html

相关文章

Spring Boost + Elasticsearch 实现检索查询

需求&#xff1a;对“昵称”进行“全文检索查询”&#xff0c;对“账号”进行“精确查询”。 认识 Elasticsearch 1. ES 的倒排索引 正向索引 对 id 进行检索速度很快。对其他字段即使加了索引&#xff0c;只能满足精确查询。模糊查询时&#xff0c;逐条数据扫描&#xff0c…

redis实现未支付时间超时就删除订单,并给前端反应一个已过期

1.创建订单缓存&#xff0c;设置过期时间为一分钟 now 是一个表示当前时间的对象&#xff0c;offset 方法用于对当前时间进行偏移。 redisTemplate.expireAt(paymentKey, now.offset(DateField.SECOND, 60)); 2.创建KeyExpiredListener类并且继承KeyExpirationEventMessageLis…

Altair:Python数据可视化库的魅力之旅

目录 一、引言 二、Altair概述 三、Altair的核心特性 1.声明式语法 2.丰富的图表类型 3.交互式与响应式 4.无缝集成 四、案例与代码实践 案例一&#xff1a;使用Altair绘制折线图 案例二&#xff1a;使用Altair绘制热力图 五、新手入门指南 1.安装与导入 2.数据准…

【QT进阶】Qt http编程之实现websocket client客户端

往期回顾 【QT进阶】Qt http编程之nlohmann json库使用的简单介绍-CSDN博客 【QT进阶】Qt http编程之websocket的简单介绍-CSDN博客 【QT进阶】Qt http编程之实现websocket server服务器端-CSDN博客 【QT进阶】Qt http编程之实现websocket client客户端 一、最终效果 通过给定…

Idea:通义千问插件

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 一、通义千问大模型 二、程序编写助手 三、Idea安装通义千问插件 总结 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、通义千问大模型…

Cache缓存

在计算机架构中&#xff0c;缓存&#xff08;Cache&#xff09;是一种高速数据存储层&#xff0c;它存储了一部分从原始数据源&#xff08;如主内存&#xff09;频繁访问的数据副本。通过将数据暂时存储在物理上更接近处理器的位置&#xff0c;缓存能够减少数据访问的延迟&…

解决常见的 `npm install` 报错

解决常见的 npm install 报错 在 Node.js 项目中&#xff0c;我们经常使用 npm install 命令来安装项目所需的依赖包。然而&#xff0c;有时候在执行这个命令时会遇到一些问题和报错。本文将介绍一些常见的 npm install 报错&#xff0c;并提供相应的解决方法。 报错 1: “ER…

全额退款20000,what?

接单的时候有多兴奋&#xff0c;退单的时候就有多落寞。今天我对客户全额退款了&#xff0c;跟踪了10天的项目正式结束。 这是我接单以来项目单价最高的一个项目&#xff0c;本来不太想接的&#xff0c;因为业务领域不擅长&#xff0c;又想挑战一下。兜兜转转找了几个人因为各种…