设计模式:单例模式和观察者模式实现方式以及优化

单例模式

一个类 ,从头到尾 能有一个对象,全世界共用这一个实例。

类的所有成员函数(包括普通成员函数、友元函数)、内部定义的代码,都属于「类的作用域」,在这个作用域内可以直接访问该类对象的 私有(private) 保护(protected)成员,不受访问权限限制。

类内部static 成员变量 ,只是声明不是定义

不占内存 ,必须在类外部全局作用域再定义 一次,才会真正分配空间

饥汉模式

main()没执行 时,对象已经被创建初始化

全局

cpp 复制代码
class MyObject
{
private:
    int value;
    static MyObject objx;
​
    MyObject(int x = 0) :value(x)
    {
        cout << "Create MyObject:" << this << endl;
    }
    
    //无 拷贝构造和 赋值运算符重载
    MyObject(const MyObject& it) = delete;
    MyObject& operator=(const MyObject& it) = delete;//c++11
public:
    ~MyObject()
    {
        cout << "Destroy MyObject:"  <<this<< endl;
    }
    int& Value() { return value; }
    const int& Value()const { return value; }
    //void Print(cosnt MyObject *const this)
    void Print()const//const  --->修饰this的指向
    {
        cout << "value:" << value<< endl;
    }   
    
    //公共调用同一对象的 接口
    static MyObject& getObject()
    {
        return objx;
    }
};
​
MyObject MyObject::objx(10);
​
//多线程安全---->只初始化一次
void threadfunc1()
{
    MyObject& obj1=MyOject::getObject();
    obj1.Print();
}
void threadfunc2()
{
    MyObject& obj2=MyOject::getObject();
    obj2.Print();
}
​
int main()
{
    MyObject& obj1=MyObject::getObject();//引用绑定
    MyObject& obj2 = MyObject::getObject();
    cout << "obj1:" << &obj1 << endl;
    cout << "obj2:" << &obj2 << endl;
    //只创建一个对象
    return 0;
}

懒汉模式

  • 构造函数私有无参数

  • 公共 静态函数 进行初始构造

  • 调用时 构造

函数内static对象

cpp 复制代码
#include <iostream>
#include <thread>
#include <cstdlib>
#include <ctime>
#include <chrono>
using namespace std;
​
class MyObject
{
private:
    int value;
​
    // 构造函数无参!!!(关键)
    MyObject() : value(0)
    {
        cout << "Create MyObject: " << this << endl;
    }
​
    MyObject(const MyObject& it) = delete;
    MyObject& operator=(const MyObject& it) = delete;
​
public:
    ~MyObject()
    {
        cout << "Destroy MyObject: " << this << endl;
    }
​
    int& Value() { return value; }
    const int& Value() const { return value; }
​
    void Print() const
    {
        cout << "value: " << value << endl;
    }
​
    // 真正线程安全的单例(无参构造)
    static MyObject& getObject()
    {
        static MyObject objx;
        return objx;
    }
​
    // 赋值用函数
    void setValue(int x)
    {
        value = x;
    }
};
​
void threadfun1()
{
    MyObject& obj1 = MyObject::getObject();
    obj1.setValue(10);
    obj1.Print();
}
void threadfun2()
{
    MyObject& obj2 = MyObject::getObject();
    obj2.setValue(20);
    obj2.Print();
}
​
int main()
{
    thread tha(threadfun1);
    thread thb(threadfun2);
​
    tha.join();
    thb.join();
​
    return 0;
}

指针+加锁版本

cpp 复制代码
#include <mutex>
​
class MyObject
{
private:
    static MyObject* inst;
    static std::mutex mtx;  // 锁   一份
​
    MyObject() {}
​
public:
    /*
    static MyObject* getObject()
    {
        std::lock_guard<std::mutex> lock(mtx); // 每次都加锁
​
        if (inst == nullptr)
        {
            inst = new MyObject();
        }
        return inst;
    }*/
    static MyObject* getObject()
    {
        if (inst == nullptr)        // 第一次不加锁检查
        {
            std::lock_guard<std::mutex> lock(mtx);
            if (inst == nullptr)    // 第二次加锁检查
            {
                inst = new MyObject();
            }
        }//lock_guard 锁在进入 {} 时上锁,离开 } 时自动释放。
        return inst;
    }
​
};
​
// 静态成员初始化
MyObject* MyObject::inst = nullptr;
std::mutex MyObject::mtx;
老式指针 + 锁 函数内 static 对象
线程安全 要自己加锁 ✅ 天然安全
效率 低 / 一般 ✅ 最高
析构 不会自动析构 ✅ 自动析构
代码 复杂 ✅ 极简
内存泄漏 可能 ✅ 没有

观察者模式

发布、订阅模式

将所有人注册到一个容器中,每个人都有updata()

裸指针

cpp 复制代码
#include<iostream>
#include<assert.h>
#include<memory>
#include<vector>
#include<time.h>
#include<typeinfo>
#include<list>
#include<algorithm>
#include<string>
using namespace std;
class Subject;
class Observer
{
protected:
    string _name;
    Subject* _sub;
public:
    Observer(const std::string& name,Subject* sub):_name(name),_sub(sub){}
    virtual void updata() = 0;
};
class Subject
{
protected:
    list<Observer*>_obslist;
    bool _is_boss;
    string _mess;
public:
    Subject() :_is_boss(false), _mess("该干啥就干啥!") {}
    ~Subject() { removeObserver(); }
    void setChanged() { _is_boss = true; _mess = "老板来了!"; }
    void clearChanged() { _is_boss = false; _mess = ("该干啥就干啥!"); }
    bool hasChanged()const { return _is_boss; }
    const string& getMess()const { return _mess; }
    void addObserver(Observer* obs)
    {
        //检查观察者是否重复添加 ----> set
        _obslist.push_back(obs);
    }
    void removeObserver(Observer* obs)
    {
        auto it = find(_obslist.begin(), _obslist.end(), obs);
        if (it != _obslist.end())
        {
            _obslist.erase(it);
        }
    }
    void removeObserver()
    {
        _obslist.clear();
    }
    size_t countObject()const
    {
        return _obslist.size();
    }
    virtual void notify() = 0;
};
class Secretary :public Subject
{
public:
    void notify()
    {
        for (auto& obs : _obslist)
        {
            obs->updata();
        }
    }
};
class StockObserver :public Observer
{
public:
    StockObserver(const std::string& name, Subject* sub):Observer(name,sub){}
    void updata()
    {
        cout << _name << "收到消息" << endl;
        if (_sub->hasChanged())
        {
            cout << _sub->getMess() << "马上关闭炒股软件,装做很认真工作的样子!" << endl;
        }
        else
        {
            cout << "老板没来" << _sub->getMess() << endl;
        }
    }
};
class NBAObserver :public Observer
{
public:
    NBAObserver(const std::string& name, Subject* sub) :Observer(name, sub) {}
    void updata()
    {
        cout << _name << "收到消息" << endl;
        if (_sub->hasChanged())
        {
            cout << _sub->getMess() << "马上关闭NBA,装做很认真工作的样子!" << endl;
        }
        else
        {
            cout << "老板没来" << _sub->getMess() << endl;
        }
    }
};
​
int main()
{
    Subject* dwq = new Secretary();
    Observer* xs = new NBAObserver("小帅",dwq);
​
    Observer* lm = new NBAObserver("小明", dwq);
​
    Observer* xf = new StockObserver("小芳", dwq);
​
    dwq->addObserver(xs);
    dwq->addObserver(lm);
    dwq->addObserver(xf);
​
    dwq->notify();
    printf("\n=============================================\n");
    dwq->setChanged();
    dwq->notify();
    printf("\n=============================================\n");
    dwq->clearChanged();
    dwq->notify();
    printf("\n=============================================\n");
    return 0;
}

智能指针

观察者 ----------->关联发布者

weak_ptr ------>观察 二者是否关联,避免造成发布者被删除

cpp 复制代码
class Subject;
class Observer
{
protected:
    string _name;
    //shared_ptr<Subject> _sub;
    //观察者消失,但生产者依然存在
    weak_ptr<Subject> _sub;
public:
    Observer(const std::string& name, weak_ptr<Subject> sub) :_name(name), _sub(sub)
    {
        cout << "Create Observer" << endl;
    }
    virtual void updata() = 0;
    virtual ~Observer()
    {
        cout << "Destory Observer" << endl;
    }
};
class Subject
{
protected:
    list<shared_ptr<Observer>>_obslist;
    //list<unique_ptr<Observer>>_obslist;
    //进行插入 需要扩容 时,底层不确定时 拷贝构造  还是 移动构造
    //unique_ptr---->删除 拷贝构造 和 赋值重载
    bool _is_boss;
    string _mess;
public:
    Subject() :_is_boss(false), _mess("该干啥就干啥!") 
    {
        cout << "Create Subject" << endl;
    }
    void setChanged() { _is_boss = true; _mess = "老板来了!"; }
    void clearChanged() { _is_boss = false; _mess = ("该干啥就干啥!"); }
    bool hasChanged()const { return _is_boss; }
    const string& getMess()const { return _mess; }
    void addObserver(shared_ptr<Observer> obs)
    {
        //检查观察者是否重复添加 ----> set
        _obslist.push_back(obs);
    }
    void removeObserver(shared_ptr<Observer> obs)
    {
        auto it = find(_obslist.begin(), _obslist.end(), obs);
        if (it != _obslist.end())
        {
            _obslist.erase(it);
        }
    }
    void removeObserver()
    {
        _obslist.clear();
    }
    size_t countObject()const
    {
        return _obslist.size();
    }
    virtual void notify() = 0;
    virtual ~Subject()
    {
        removeObserver();
        cout << "Destory Subject" << endl;
    }
};
class Secretary :public Subject
{
public:
    Secretary()
    {
        cout << "Create Secretary" << endl;
    }
    void notify()
    {
        for (auto& obs : _obslist)
        {
            obs->updata();
        }
    }
    ~Secretary()
    {
        cout << "Destory Secretary" << endl;
    }
};
class StockObserver :public Observer
{
public:
    StockObserver(const std::string& name, weak_ptr<Subject> sub) :Observer(name, sub)
    {
        cout << "Create StockObserver" << endl;
    }
    
    void updata()
    {
        cout << _name << "收到消息" << endl;
        shared_ptr<Subject>sub = _sub.lock();//判断对象是否存活
        if (sub == nullptr) { return; }
        if (sub->hasChanged())
        {
            cout << sub->getMess() << "马上关闭炒股软件,装做很认真工作的样子!" << endl;
        }
        else
        {
            cout << "老板没来" << sub->getMess() << endl;
        }
    }
    ~StockObserver()
    {
        cout << "Destory StockObserver" << endl;
    }
};
class NBAObserver :public Observer
{
public:
    NBAObserver(const std::string& name, weak_ptr<Subject> sub) :Observer(name, sub)
    {
        cout << "Create NBAObserver" << endl;
    }
    void updata()
    {
        cout << _name << "收到消息" << endl;
        shared_ptr<Subject>sub = _sub.lock();//判断对象是否存活
        if (sub == nullptr) { return; }
        if (sub->hasChanged())
        {
            cout << sub->getMess() << "马上关闭NBA,装做很认真工作的样子!" << endl;
        }
        else
        {
            cout << "老板没来" << sub->getMess() << endl;
        }
    }
    ~NBAObserver()
    {
        cout << "Destory NBAObserver" << endl;
    }
};
​
int main()
{
    shared_ptr<Subject> dwq = make_shared<Secretary> ();
    shared_ptr<Observer> xs = make_shared<NBAObserver>("小帅", dwq);
​
    shared_ptr<Observer> lm = make_shared< NBAObserver>("小明", dwq);
    shared_ptr<Observer> xf = make_shared<StockObserver>("小芳", dwq);
​
    dwq->addObserver(xs);
    dwq->addObserver(lm);
    dwq->addObserver(xf);
​
    dwq->notify();
    printf("\n=============================================\n");
    dwq->setChanged();
    dwq->notify();
    printf("\n=============================================\n");
    dwq->clearChanged();
    dwq->notify();
    printf("\n=============================================\n");
    dwq->removeObserver(xs);
    dwq->notify();
    printf("\n=============================================\n");
    return 0;
}

多线程+门闩+锁

cpp 复制代码
std::latch my_latch(2);
mutex mtx;
void func_xs(shared_ptr<Subject>dwq)
{
    shared_ptr<Observer> xs = make_shared<StockObserver>("小帅", dwq);
    dwq->addObserver(xs);
    my_latch.count_down();
    int n = rand() % 100;
    while (n-- != 0)
    {
        //阻塞
        std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 100));
        ///this_thread::yield(); 主动让度CPU----->就绪态
        lock_guard<mutex> locker(mtx);
        cout << xs->getname() << endl;
    }
}
void func_xm(shared_ptr<Subject>dwq)
{
    shared_ptr<Observer> xm = make_shared<StockObserver>("小明", dwq);
    dwq->addObserver(xm);
    my_latch.count_down();
    int n = rand() % 100;
    while (n-- != 0)
    {
        //阻塞
        std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 100));
        //this_thread::yield(); //主动让度CPU----->就绪态
        lock_guard<mutex> locker(mtx);
        cout << xm->getname() << endl;
    }
}
void func_sec(shared_ptr<Subject>dwq)
{
    my_latch.wait();
    int n = rand() % 100;
    while (n-- != 0)
    {
        if (rand() % 2 == 0)
        {
            dwq->setChanged();
        }
        else
        {
            dwq->clearChanged();
        }
        dwq->notify();
        lock_guard<mutex> locker(mtx);
        cout << "\n======================================\n";
        this_thread::sleep_for(chrono::milliseconds( rand() % 100));
    }
​
}
int main()
{
    shared_ptr<Subject>dwq = make_shared<Secretary>();
    srand(time(nullptr));
    std::thread thxs(func_xs, dwq);
    std::thread thxm(func_xm, dwq);
    std::thread thsec(func_sec, dwq);
    cout << "count:" << dwq->countObject() << endl;
    thxs.join();
    thxm.join();
    thsec.join();
​
    return 0;
}
相关推荐
W.W.H.2 小时前
Qt 应用防多开:极简单例方案
开发语言·qt·单例模式·共享内存
doubledong19942 小时前
分形世界与设计模式
设计模式
多加点辣也没关系3 小时前
设计模式-访问者模式
设计模式·访问者模式
咖啡八杯3 小时前
GoF设计模式——原型模式
java·后端·设计模式·原型模式
多加点辣也没关系3 小时前
设计模式-状态模式
设计模式·状态模式
多加点辣也没关系3 小时前
设计模式-备忘录模式
设计模式·备忘录模式
雪度娃娃3 小时前
行为型设计模式——中介者模式
microsoft·设计模式·中介者模式
多加点辣也没关系3 小时前
设计模式-中介者模式
设计模式·中介者模式
geovindu21 小时前
go: Read-Write Lock Pattern
开发语言·后端·设计模式·golang·读写锁模式