单例模式--创建型模式

1、描述

单例是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。单例拥有与全局变量相同的优缺点。 尽管它们非常有用, 但却会破坏代码的模块化特性。

优点:由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁的创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。

缺点:单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。

单例模式与单一职责原则有冲突。一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是要单例取决于环境,单例模式把“要单例”和业务逻辑融合在一个类中。

2、结构图

3、C++代码

在muduo库中有一个单例类模板,可以参考https://blog.csdn.net/qu1993/article/details/109476614

下面是一个使用互斥锁实现的线程安全的单例类,这个例子是最后提到的网站上的例子,但我觉得这个例子不太好,还是使用pthread_once实现更容易一些,或者干脆使用一个静态变量得了

#include <string>
#include <mutex>
#include <iostream>
#include <thread>


//单例类定义GetInstance替代构造函数,并允许用户反复使用该类的同一实例
class Singleton
{


private:
    static Singleton * pinstance_;
    static std::mutex mutex_;

    //单例的构造函数和析构函数总是定义为私有的,防止直接创建该类的对象
protected:
    Singleton(const std::string value): value_(value)
    {
    }
    ~Singleton() {}
    std::string value_;

public:
    //不能使用拷贝构造函数
    Singleton(Singleton &other) = delete;
    
    //不能使用赋值运算符
    void operator=(const Singleton &) = delete;

    //静态方法,提供访问单例的方式。第一次会创建一个单例对象,之后再调用都是返回该对象
    static Singleton *GetInstance(const std::string& value);
    
    //业务逻辑
    void SomeBusinessLogic()
    {
        // ...
    }
    
    std::string value() const{
        return value_;
    } 
};


Singleton* Singleton::pinstance_{nullptr};
std::mutex Singleton::mutex_;


Singleton *Singleton::GetInstance(const std::string& value)
{
    std::lock_guard<std::mutex> lock(mutex_);
    if (pinstance_ == nullptr)
    {
        pinstance_ = new Singleton(value);
    }
    return pinstance_;
}

void ThreadFoo(){
    // 下面的代码模拟缓慢的初始化。
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    Singleton* singleton = Singleton::GetInstance("FOO");
    std::cout << singleton->value() << "\n";
}

void ThreadBar(){
    // 下面的代码模拟缓慢的初始化。
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    Singleton* singleton = Singleton::GetInstance("BAR");
    std::cout << singleton->value() << "\n";
}

int main()
{   
    std::cout <<"If you see the same value, then singleton was reused (yay!\n" <<
                "If you see different values, then 2 singletons were created (booo!!)\n\n" <<
                "RESULT:\n";   
    std::thread t1(ThreadFoo);
    std::thread t2(ThreadBar);
    t1.join();
    t2.join();
    
    return 0;
}

下面这个是我仿照网站上的例子使用pthread_once实现的单例:

#include <string>
#include <iostream>
#include <pthread.h>
//单例类定义GetInstance替代构造函数,并允许用户反复使用该类的同一实例
class Singleton
{
private:
    //单例的构造函数和析构函数总是定义为私有的,防止直接创建该类的对象
    Singleton() {}
    ~Singleton() {}

public:
    //不能使用拷贝构造函数
    Singleton(Singleton &other) = delete;
    
    //不能使用赋值运算符
    void operator=(const Singleton &) = delete;

    //静态方法,提供访问单例的方式。第一次会创建一个单例对象,之后再调用都是返回该对象
    static Singleton &Instance();

    //业务逻辑
    void SomeBusinessLogic()
    {
        // ...
    }
    
    std::string GetValue() const{
        return value_;
    }

    void SetValue(std::string value) {
    	value_ = value;
    }
private:
    static void Init(); 

private:
    std::string value_;
    static pthread_once_t ponce_;
    static Singleton* instance_;
};


pthread_once_t Singleton::ponce_ = PTHREAD_ONCE_INIT;
Singleton* Singleton::instance_ = NULL;

Singleton &Singleton::Instance()
{
    pthread_once(&ponce_, Init);
    return *instance_;
}

void Singleton::Init()
{
    instance_ = new Singleton();
}

int main()
{
    Singleton::Instance().SetValue("hello");
    std::cout << Singleton::Instance().GetValue() << std::endl;
}

参考

https://refactoringguru.cn/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值