设计模式

设计模式:是指在软件开发中,通过验证的,用于解决特定环境下、反复重现的、特定问题的解决方案
咱们要留神:不要为了套用设计模式而应用设计模式,在业务遇到问题时,要自然而然想到设计模式作为一种解决方案

为什么要学设计模式

  • 设计模式曾经成为软件开发人员的规范词汇
  • 学习设计模式是集体技术能力进步的路径
  • 不必反复造轮子
  • 各种源码当中充斥着各种设计模式

观察者模式

定义对象间的一种一对多(变换)的依赖关系,以便当一个对象(subject)的状态产生扭转时,所有依赖于它的对象都失去告诉并且自动更新

应用场景


当用户订阅了某种音讯,当音讯有扭转的时候,就会告诉用户音讯状态的扭转,并且执行用户对应音讯扭转所须要的行为
要点

  1. 应用面向对象的形象,observer模式使咱们能够独立的扭转指标与观察者,从而使得两者之间的依赖能够达到松耦合。
  2. 指标指定发送告诉时,无需指定观察者,告诉会主动流传
  3. 观察者能够决定是否须要订阅告诉,指标对象对此无所不知。

推模式和拉模式

  1. 推模式: 指标对象向观察者推送指标的详细信息,不论观察者是否须要,相当于计算机网络中的播送。
  2. 拉模式: 指标在告诉观察者的时候只传递大量信息。如果观察者须要更具体的信息,应该是观察者本身向指标对象获取。

源码

#include <iostream>#include <list>#include <string>using namespace std;class Subject;class Observer{public:    Observer() {}    virtual ~Observer() {}    virtual void update(Subject *sj) = 0;    virtual void update(string content) = 0;};class Subject{public:    Subject() {}    virtual ~Subject() {}    virtual string getcontent() = 0;    virtual string getAbstractContent() = 0;    void attach(Observer *ob)    {        observers.push_back(ob);    }    void detach(Observer *ob)    {        observers.remove(ob);    }    virtual void notifyObservers()    {        for (Observer *ob : observers)        {            ob->update(this); //拉模型,具体数据让观察者本人去取        }    }    virtual void notifyObservers(string content)    {        for (Observer *ob : observers)        {            ob->update(content); //推模型 数据是由被观察者抉择        }    }private:    list<Observer *> observers;};class Reader : public Observer{public:    Reader(string name) : _readername(name) {}    virtual ~Reader() {}    virtual void update(Subject *sj)    {        cout << _readername << " 开始浏览整个" << sj->getcontent() << endl;    }    virtual void update(string content)    {        cout << _readername << " 开始浏览报纸简介" << endl;    }private:    string _readername;};class paper : public Subject{public:    paper() {}    virtual ~paper() {}    void setcontent(string content)    {        this->content = content;    }    virtual string getcontent()    {        return content;    }    virtual string getAbstractContent()    {        return "摘要";    }private:    string content;};int main(){    paper newpaper;    newpaper.setcontent("今日头条");    Reader read1("user1"), read2("user2");    newpaper.attach(&read1); //订阅    newpaper.attach(&read2); //订阅    newpaper.notifyObservers();    return 0;}

工厂模式

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化提早(目标:解耦,伎俩:虚函数)到子类。

动机

  • 在软件系统中,常常面临创建对象的工作。因为需要的变换,须要创立的对象的具体类型常常变换。
  • 如何应答这种变动?如何绕过惯例的对象创立办法,提供一种"封装机制"来防止客户程序和这种"具体对象创立工作"的紧耦合。

应用场景

  • 数据导出各种格局
  • 领取接口,可能对应不同的领取网关:支付宝,财付通,网银在线等等。

要点总结

  • factory method模式用于隔离对象的使用者和具体类型之间的耦合关系。面对一个常常变动的具体类型,紧耦合关系会导致软件的软弱
  • factory method模式通过面对对象的形式,将所要创立的具体对象工作提早到子类,从而实现一种扩大的策略,较好的解决了耦合关系。
  • factory method模式解决了单个模式的需要变动。毛病在于要求创立形式/参数雷同。

代码

#include <iostream>using namespace std;class ExportFileProduct{public:    ExportFileProduct() {}    virtual ~ExportFileProduct() {}    virtual bool Export(string data) = 0;};class ExportTextProduct : public ExportFileProduct{public:    ExportTextProduct() {}    virtual ~ExportTextProduct(){};    virtual bool Export(string data)    {        cout << "导出数据[" << data << "]保留成文本的形式" << endl;        return true;    }};class ExportDBProduct : public ExportFileProduct{public:    ExportDBProduct() {}    virtual ~ExportDBProduct(){};    virtual bool Export(string data)    {        cout << "导出数据[" << data << "]保留成数据库的形式" << endl;        return true;    }};class ExportJsonProduct : public ExportFileProduct{public:    ExportJsonProduct() {}    virtual ~ExportJsonProduct() {}    virtual bool Export(string data)    {        cout << "导出数据:[" << data << "]保留Json的形式" << endl;        return true;    }};class ExportFactory{public:    ExportFactory() {}    virtual ~ExportFactory() {}    bool Export(int type, string data)    {        ExportFileProduct *product = factoryMethod(type);        bool ret = false;        if (product)        {            ret = product->Export(data);        }        else        {            cout << "没有对应的类型" << endl;        }        return ret;    }protected:    virtual ExportFileProduct *factoryMethod(int type)    {        ExportFileProduct *product;        if (type == 1)        {            product = new ExportTextProduct();        }        else if (type == 2)        {            product = new ExportDBProduct();        }        else if (type == 3)        {            product = new ExportJsonProduct();        }        return product;    }};

单例模式

保障一个类只有一个实例,并提供一个该实例的全局拜访点

动机

  • 在软件系统中,常常有这样一些非凡的类,必须确保他们在零碎中只存在一个实例,能力确保他们的逻辑正确性,以及良好的效率。
  • 绕过惯例的结构器,提供一种机制来保障一个类只有一个实例。
  • 类设计者的责任 而不是使用者的责任

常见写法

饿汉式单例

程序开始运行时就创立单例

class Singleton4{private:    Singleton4() = default;    Singleton4(const Singleton4 &s) = delete;    Singleton4 &operator=(Singleton4 &s) = delete;    static Singleton4 _singleton;private:    static Singleton4 *getinstance()    {        return &_singleton;    }};Singleton4 Singleton4::_singleton;
懒汉式单例

应用单例时才开始创立

双锁型单例模式
/* 双查看锁,但因为内存读写reorder不平安 因为C++创建对象时,会执行1、分配内存,2 调用结构,3 赋值操作三步操作,然而古代CPU和编译器高并发下可能会进行乱序重排操作,因此创建对象new CSingleton的第2步可能会晚于第3步进行指令调用,因此导致呈现未定义的的行为。*/class Singleton3{private:    static Singleton3 *_singleton;    static mutex _mutex;    Singleton3() = default;    Singleton3(const Singleton3 &s) = delete;    Singleton3 &operator=(const Singleton3 &s) = delete;    class GarbageCollector    {    public:        ~GarbageCollector()        {            cout << "~GarbageCollector()\n";            if (Singleton3::_singleton)            {                cout << "free singleton";                delete Singleton3::_singleton;                Singleton3::_singleton = nullptr;            }        }    };    static GarbageCollector _gc; //模仿gc来回收单例public:    static Singleton3 *getinstance()    {        //Singleton* tmp = m_instance.load(std::memory_order_relaxed);        //std::atomic_thread_fence(std::memory_order_acquire);//获取内存fence 能够使得高并发下不会呈现内存读写reorderdd        if (_singleton == nullptr)        {            _mutex.lock(); //对象的new不是原子操作 1、分配内存,2 调用结构,3 赋值操作,到第3步的时候才是m_singleton非空            //  1、分配内存,2 赋值操作 3 调用结构,到第2步的时候才是m_singleton非空            if (_singleton == nullptr)            {                _singleton = new Singleton3();            }            _mutex.unlock();        }        return _singleton;    }};Singleton3 *Singleton3::_singleton = nullptr;Singleton3::GarbageCollector Singleton3::_gc;mutex Singleton3::_mutex;

在高并发下双锁型单例模式可能因为内存读写reorder造成隐患

线程平安型单例
class Singleton2{private:    static Singleton2 *_singleton;    static mutex _mutex;    Singleton2() = default;    Singleton2(const Singleton2 &s) = delete;    Singleton2 &operator=(const Singleton2 &s) = delete;    class GarbageCollector    {    public:        ~GarbageCollector()        {            cout << "~GarbageCollector()\n";            if (Singleton2::_singleton)            {                cout << "free singleton";                delete Singleton2::_singleton;                Singleton2::_singleton = nullptr;            }        }    };    static GarbageCollector _gc; //模仿gc来回收单例public:    static Singleton2 *getinstance()    {        _mutex.lock(); // 加锁的粒度大,效率较低, 对高并发的拜访        if (_singleton == nullptr)        {            _singleton = new Singleton2();        }        _mutex.unlock();        return _singleton;    }};Singleton2 *Singleton2::_singleton = nullptr;Singleton2::GarbageCollector Singleton2::_gc;mutex Singleton2::_mutex;

加锁之后在并发高的场景,效率很低,个别不举荐这种写法

线程不平安懒汉式
class Singleton1{private:    static Singleton1 *_singleton;    Singleton1() = default;    Singleton1(const Singleton1 &s) = delete;    Singleton1 &operator=(const Singleton1 &s) = delete;    class GarbageCollector    {        //线程不平安    public:        ~GarbageCollector()        {            cout << "~GarbageCollector()\n";            if (Singleton1::_singleton)            {                cout << "free singleton";                delete Singleton1::_singleton;                Singleton1::_singleton = nullptr;            }        }    };    static GarbageCollector _gc; //模仿gc来回收单例public:    static Singleton1 *getinstance()    {        if (_singleton == nullptr)        {            _singleton = new Singleton1();        }        return _singleton;    }};Singleton1 *Singleton1::_singleton = nullptr;Singleton1::GarbageCollector Singleton1::_gc;
局部变量的懒汉式

举荐写法

class Singleton{private:    Singleton(){};    Singleton(const Singleton &s) = delete;    Singleton &operator=(Singleton &s) = delete;public:    static Singleton *getinstance()    {        static Singleton _singleton;        return &_singleton;    }};

有一些坑,如果应用隐式构造函数导致部分动态变量不平安,读者能够自行编译成汇编 看看该局部变量有没有加锁

要点总结
  • singleton模式中实例结构器能够设置为protected以容许子类派生
  • singleton模式个别不要反对拷贝构造函数和clone接口,因为有可能导致多个实例对象,与singleton模式的初衷违反。
  • 隐式构造函数导致函数部分动态变量不平安。