代码操作中经常使用到设计模式之单例模式

简介: 代码操作中经常使用到设计模式之单例模式

前言:

应一位朋友之邀继续分享一下设计模式,关于设计模式的基本介绍在上一篇文章已经有所描述,这篇就不多做赘述。今天给大家介绍一下设计模式的里面的入门篇——单例模式。学习这些模式有助于经验不足的开发人员通过一种简单快捷的方式来学习软件设计。

作者:良知犹存

转载授权以及围观:欢迎关注微信公众号:羽林君

或者添加作者个人微信:become_me


单例模式概念定义

单例模式是我们用到最简单的设计模式之一,这种类型的设计模式属于创建者类型模式。指定一个类只有一个实例,且该类能自行创建这个实例。

例如,我们在一些应用编程时候会定义一些独一无二的驱动类,这个类只会有一个实例产生,通过使用单例模式,我们就可以避免因为不需要的多次实例化这个类减少内存的浪费,或者造成数据的不一致。

结构定义:

单例类:包含一个实例且能自行创建这个实例的类。

访问类:使用单例的类。

结构图如下4edc953e2c684bbe819ffa954c899c08.png

之一。通常,普通类的构造函数是公有的,外部类可以通过“new 构造函数()”来生成多个实例。但是,如果将类的构造函数设为私有的,外部类就无法调用该构造函数,也就无法生成多个实例。这时该类自身必须定义一个静态私有实例,并向外提供一个静态的公有函数用于创建或获取该静态私有实例。

下面介绍一些常用的单例模式使用的代码例子:

第 1 种:懒汉式单例

该模式的特点是类加载时没有生成单例,只有当第一次调用 getlnstance 方法时才去创建这个单例。

范例如下:

C++实现

#include <iostream>
using namespace std;
class Signleton {
private:
 Signleton() { cout << "init singleton" << endl; 
 }
 static Signleton* _instance;
public:
 static Signleton* getInstance() {
  if(_instance == nullptr) {
   _instance = new Signleton;
  }
  return _instance;
 }
};
Signleton * Signleton:: _instance = nullptr;
int main() {
//  Signleton obj1; //这样定义会报错,调用用下面方式
  Signleton::getInstance();
  Signleton::getInstance();
  Signleton::getInstance();
  return 0;
}

python实现

#!/usr/bin/python3
class Singleton(object):
    def __init__(self):
        print("init singleton")
    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            Singleton._instance = Singleton(*args, **kwargs)
        return Singleton._instance
if __name__ == "__main__":
    obj1 = Singleton.instance()
    obj2 = Singleton.instance()
    obj3 = Singleton.instance()

第 2 种:饿汉式单例

该模式的特点是类一旦加载就创建一个单例,保证在调用 getInstance 方法之前单例已经存在了。

范例如下:

C++实现

#include <iostream>
using namespace std;
class Signleton {
private:
 Signleton() { cout << "init singleton" << endl; 
 }
 static Signleton _instance;
public:
     static Signleton getInstance() {
  return _instance;
 }
};
Signleton  Signleton:: _instance ;
int main() {
  Signleton::getInstance();
  Signleton::getInstance();
  Signleton::getInstance();
  return 0;
}

python实现

#!/usr/bin/python3
class Singleton(object):
    _instance = None
    def __init__(self):
        if not Singleton._instance:
            print("init singleton")
    @classmethod
    def instance(cls):
        if not cls._instance:
            cls._instance = Singleton()
        return cls._instance
if __name__ == "__main__":
    obj1 = Singleton.instance()
    obj2 = Singleton.instance()
    obj3 = Singleton.instance()
    print(Singleton.instance())
    print(Singleton.instance())
    print(Singleton.instance())

编译之后可以看到,我们调用了三次,但是实际上构造函数只执行了一次。


两种创建单例对象的方式对比:


懒汉式:只有这个类在被调用的时候才会创建,若是多线程同时使用,就会考虑线程安全的为题。这个代码只适合在单线程下,当多线程时,是不安全的,多线程加锁。考虑两个线程同时首次调用instance方法且同时检测到p是nullptr,则两个线程会同时构造一个实例给p,这将违反了单例的准则。


饿汉式:当成类被加载的时候,这个类就会被实例化,虽然没有被使用但是会占用内存,由于是一开始就会被实例化了,所以这个线程安全的。


第 3 种:优化版本(我经常使用的版本)


范例如下:


C++实现

#include <iostream>
using namespace std;
class Signleton {
private:
 Signleton() {
   cout << "init singleton" << endl; 
 }
public:
     static Signleton getInstance() {
        static  Signleton m_instance;
        return m_instance;
 }
};
Signleton  Signleton:: _instance ;
int main() {
  Signleton::getInstance();
  Signleton::getInstance();
  Signleton::getInstance();
  return 0;
}

这个在工作中经常使用,使用了一个局部static变量,代码也比较简洁,优先推荐这个给大家使用。

补充:C++中static对象的初始化

non-local static对象(函数外)

C++规定,non-local static 对象的初始化发生在main函数执行之前,也即main函数之前的单线程启动阶段,所以不存在线程安全问题。但C++没有规定多个non-local static 对象的初始化顺序,尤其是来自多个编译单元的non-local static对象,他们的初始化顺序是随机的。

local static 对象(函数内)

对于local static 对象,其初始化发生在控制流第一次执行到该对象的初始化语句时。多个线程的控制流可能同时到达其初始化语句。

在C++11之前,在多线程环境下local static对象的初始化并不是线程安全的。具体表现就是:如果一个线程正在执行local static对象的初始化语句但还没有完成初始化,此时若其它线程也执行到该语句,那么这个线程会认为自己是第一次执行该语句并进入该local static对象的构造函数中。这会造成这个local static对象的重复构造,进而产生内存泄露问题。所以,local static对象在多线程环境下的重复构造问题是需要解决的。

而C++11则在语言规范中解决了这个问题。C++11规定,在一个线程开始local static 对象的初始化后到完成初始化前,其他线程执行到这个local static对象的初始化语句就会等待,直到该local static 对象初始化完成。

单例模式的优点和缺点

单例模式的优点:

单例模式可以保证内存里只有一个实例,减少了内存的开销。

可以避免对资源的多重占用。

单例模式设置全局访问点,可以优化和共享资源的访问。

单例模式的缺点:

单例式一般没有接口,扩展困难。如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则。

在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象。

单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。

结语

这就是我分享的设计模式中的单例模式,如果大家有更好的想法和需求,也欢迎大家加我好友交流分享哈。


作者:良知犹存,白天努力工作,晚上原创公号号主。公众号内容除了技术还有些人生感悟,一个认真输出内容的职场老司机,也是一个技术之外丰富生活的人,摄影、音乐 and 篮球。关注我,与我一起同行。

目录
相关文章
|
1月前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
27 2
|
12天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
|
20天前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入理解与应用
【10月更文挑战第22天】 在软件开发中,设计模式是解决特定问题的通用解决方案。本文将通过通俗易懂的语言和实例,深入探讨PHP中单例模式的概念、实现方法及其在实际开发中的应用,帮助读者更好地理解和运用这一重要的设计模式。
15 1
|
30天前
|
设计模式 算法 数据库连接
PHP中的设计模式:提高代码的可维护性和扩展性
【10月更文挑战第13天】 本文将探讨PHP中常见的设计模式及其在实际项目中的应用。通过对比传统编程方式,我们将展示设计模式如何有效地提高代码的可维护性和扩展性。无论是单例模式确保类的单一实例,还是观察者模式实现对象间的松耦合,每一种设计模式都为开发者提供了解决特定问题的最佳实践。阅读本文后,读者将能更好地理解和应用这些设计模式,从而提升PHP编程的效率和质量。
|
1月前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发中,设计模式是提高代码可维护性、扩展性和复用性的关键技术之一。本文将通过探讨单例模式,一种最常用的设计模式,来揭示其在PHP中的应用及优势。单例模式确保一个类仅有一个实例,并提供一个全局访问点。通过实际案例,我们将展示如何在PHP项目中有效实现单例模式,以及如何利用这一模式优化资源配置和管理。无论是PHP初学者还是经验丰富的开发者,都能从本文中获得有价值的见解和技巧,进而提升自己的编程实践。
|
1月前
|
设计模式 安全 Java
C# 一分钟浅谈:设计模式之单例模式
【10月更文挑战第9天】单例模式是软件开发中最常用的设计模式之一,旨在确保一个类只有一个实例,并提供一个全局访问点。本文介绍了单例模式的基本概念、实现方式(包括饿汉式、懒汉式和使用 `Lazy&lt;T&gt;` 的方法)、常见问题(如多线程和序列化问题)及其解决方案,并通过代码示例详细说明了这些内容。希望本文能帮助你在实际开发中更好地应用单例模式,提高代码质量和可维护性。
29 1
|
1月前
|
设计模式 缓存 数据库连接
探索PHP中的设计模式:单例模式的实现与应用
在PHP开发中,设计模式是提高代码可复用性、可维护性和扩展性的重要工具。本文将深入探讨单例模式(Singleton Pattern)的基本概念、在PHP中的实现方式以及实际应用场景。单例模式确保一个类仅有一个实例,并提供全局访问点。通过具体代码示例和详细解释,我们将展示如何在PHP项目中有效利用单例模式来解决实际问题,提升开发效率和应用性能。
|
1月前
|
设计模式 存储 测试技术
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发领域,设计模式是解决常见问题的最佳实践。本文将深入探讨单例模式,一种确保类只有一个实例的设计模式,并提供实际应用示例。我们将从单例模式的基本概念讲起,通过实际案例展示如何在PHP中实现单例模式,以及它在不同场景下的应用和优势。最后,我们会探讨单例模式的优缺点,帮助开发者在实际项目中做出明智的选择。
|
1月前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP开发领域,设计模式是解决常见问题的高效方案集合。它们不是具体的代码,而是一种编码和设计经验的总结。单例模式作为设计模式中的一种,确保了一个类仅有一个实例,并提供一个全局访问点。本文将深入探讨单例模式的基本概念、实现方式及其在PHP中的应用。
单例模式在PHP中的应用广泛,尤其在处理数据库连接、日志记录等场景时,能显著提高资源利用率和执行效率。本文从单例模式的定义出发,详细解释了其在PHP中的不同实现方法,并探讨了使用单例模式的优势与注意事项。通过对示例代码的分析,读者将能够理解如何在PHP项目中有效应用单例模式。
|
1月前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入探讨与实践
在PHP开发领域,设计模式是提升代码可读性、可维护性和扩展性的重要工具。本文聚焦于单例模式——一种确保类只有一个实例,并提供全局访问点的设计模式。我们将从定义、实现方式、应用场景以及在PHP框架中的运用等方面进行详细探讨,旨在帮助PHP开发者更好地理解和运用单例模式。