设计模式之单例、工厂、公布订阅者模式设计模式

单例模式

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

在软件系统中,常常有这样一些非凡的类,必须保障他们 在零碎中只存在一个实例,能力确保它们的逻辑正确性, 以及良好的效率

利用场景:

DBPool 、读取配置文件

单例模式分类:

  • 1、懒汉式 -- 须要应用单例的时候,才进行初始化
  • 2、饿汉式 -- 未调用单例的时候,曾经进行初始化

写一个单例模式的demo

#include <iostream>#include <mutex>#include <thread> using namespace std; //设计线程的个数#define PTHREAD_NUM  20//懒汉式 饿汉式 单例模式的选型#define SINGELTON_SELECTOR 0 //单例模式 #if SINGELTON_SELECTOR //懒汉式  -- 调用的时候才初始化class Singleton{ private:    Singleton(){        cout<<"Singleton construct  1111\n";    }    ~Singleton(){        cout<<"Singleton destruct   1111\n";    }     //禁止拷贝结构    Singleton(const Singleton &si) = delete;    //禁止等号赋值    Singleton & operator=(const Singleton &si) = delete; public:    static Singleton * getInstance(){        static Singleton m_singleton;        return &m_singleton;    }}; #else //饿汉式 -- 调用之前就曾经初始化好,调用的时候间接返回地址class Singleton{ private:    Singleton(){        cout<<"Singleton construct   2222\n";    }    ~Singleton(){        cout<<"Singleton destruct    2222\n";    }     //禁止拷贝结构    Singleton(const Singleton &si) = delete;    //禁止等号赋值    Singleton & operator=(const Singleton &si) = delete;    static Singleton m_singleton;    public:    static Singleton * getInstance(){        return &m_singleton;    }}; Singleton Singleton::m_singleton;  #endif  //定义一个互斥锁,保障只有一个线程在打印 单例变量的地址static mutex m;void print_address(){    Singleton* singleton = Singleton::getInstance();     m.lock();    cout<<singleton<<endl;    m.unlock();}//测试单例模式void test_singleton(){     thread threads[PTHREAD_NUM];    for(auto &t : threads)        t = thread(print_address);     for(auto &t : threads)        t.join();} int main(int argc,char * argv[]){     cout<<"main\n";     test_singleton(); } 

工厂模式

  • 定义一个用于创建对象的接口,让子类决定实例化哪一个类。
  • Factory Method使得一个类的实例化提早(目标:解耦,伎俩:虚函数)到子类
  • 在软件系统中,常常面临着创建对象的工作;因为需要的 变动,须要创立的对象的具体类型常常变动

    应用工厂模式提供一种“封装机制”来防止客户程序和这种“具 体对象创立工作”的紧耦合 来解决这个问题

利用场景:

  • 数据导出,导出为Excel,文本,XML
  • 领取接口,可能对应不同的领取网关

写一个工厂模式的demo

#include <iostream> using namespace std;  //工厂模式 -- 模仿一个简s单文件的解析形式//定义一个产品的概念class Parse_file{public:    Parse_file(){}    //定义虚析构函数,避免父类指针指向子类对象后,开释内存呈现内存泄露的问题    virtual ~Parse_file(){}    //定义一个接口,子类负责实现    virtual bool myparse(string data) = 0; }; //定义理论的产品 text形式解析class text_parse : public Parse_file{public:    text_parse(){}    virtual ~text_parse(){}     virtual bool myparse(string data){        cout<<"以 text 的形式保留 数据"<<data<<endl;        return true;    }    };  //定义理论的产品 xml形式解析class xml_parse : public Parse_file{public:    xml_parse(){}    virtual ~xml_parse(){}     virtual bool myparse(string data){        cout<<"以 xml 的形式保留 数据"<<data<<endl;        return true;    }};  //定义理论的产品 json形式解析class json_parse : public Parse_file{public:    json_parse(){}    virtual ~json_parse(){}     virtual bool myparse(string data){        cout<<"以 json 的形式保留 数据"<<data<<endl;        return true;    }};  //定义理论的产品 protobuf形式解析class protobuf_parse : public Parse_file{public:    protobuf_parse(){}    virtual ~protobuf_parse(){}     virtual bool myparse(string data){        cout<<"以 protobuf 的形式保留 数据"<<data<<endl;        return true;    }}; //定义工厂来生产产品class factory{public:    factory(){}    virtual ~factory(){}     //定义工厂的解析办法//便于子类继承    virtual bool myparse(int type,string data){        Parse_file * pp = nullptr;        pp = parse_method(type);         int ret = false;         if(pp){            pp->myparse(data);            delete pp;            ret = true;        }        else{            cout<<"no parse function\n";        }        return ret;    }protected://便于子类继承    virtual Parse_file * parse_method(int type){        Parse_file * pp = nullptr;        if(type == 1){            pp = new text_parse();        }else if(type == 2){            pp = new xml_parse();        }        return pp;    }}; //扩大工厂class factory2 : public factory{public:    factory2(){}    virtual ~factory2(){} protected://便于子类继承    virtual Parse_file * parse_method(int type){        Parse_file * pp = nullptr;        if(type == 3){            pp = new json_parse();        }else if(type == 4){            pp = new protobuf_parse();        }        else{            pp = factory::parse_method(type);        }        return pp;    }}; int main(){    factory * fac = new factory();    fac->myparse(1,"数据");    fac->myparse(2,"数据");    fac->myparse(3,"数据");    fac->myparse(4,"数据");     cout<<"\n\n-----------------\n\n";      factory * fac2 = new factory2();     fac2->myparse(1,"数据");    fac2->myparse(2,"数据");    fac2->myparse(3,"数据");    fac2->myparse(4,"数据");        return 0;}

成果

公布订阅模式与观察者模式

公布订阅模式和观察者模式是同一个货色吗? NONONO

  • 观察者模式里,只有两个角色 —— 观察者 + 被观察者
  • 公布订阅模式里 —— 观察者 + 两头经纪人 +被观察者

观察者模式中的推模型和拉模型:

推模型:

指标对象被动向观察者推送指标的详细信息,不 管观察者是否须要,推送的信息通常是指标对象的全副或 局部数据,相当于播送通信。

拉模型:

指标对象在告诉观察者的时候,只传递大量的信 息。如果观察者须要更具体的信息,由观察者被动到指标 对象中获取,相当于是观察者从指标对象中拉数据。个别 这种模型的实现中,会把指标对象通过update办法传递给 观察者,这样在观察者须要获取数据的时候,就能够通过 这个援用来获取了。

利用场景:

公众号告诉,淘宝告诉,知乎告诉,微信告诉等等。

写一个观察者模式的demo

//观察者模式,须要弄明确 何为观察者,何为指标//以咱们用手机看报纸为例, 咱们 是观察者, 报纸是指标//接下来咱们来模仿一下观察者模式 #include <iostream>#include <list> using namespace std; class subject; //定义形象的观察者class observer{ public:    observer(){}    virtual ~observer(){}     virtual void update(subject * sub) = 0;//读摘要    virtual void update(string content) = 0;//读内容 }; //定义一个形象的指标class subject{ public:    subject(){}    virtual ~subject(){}//设置内容    virtual int setContent(string content)=0;//失去具体内容 -- 用于推模型    virtual string getContent()=0;//失去摘要 -- 用于拉模型     virtual string getSummary()=0;//订阅    virtual void attach(observer * ob){        oblist.push_back(ob);    }//勾销订阅    virtual void detach(observer * ob){        oblist.remove(ob);    }//告诉所有订阅者 -- 推模型    virtual void notifyAllobserver(string content) {        for(auto &a : oblist){            a->update(content);        }    }//告诉所有订阅者 -- 拉模型        virtual void notifyAllobserver(){        for(observer * reader : oblist){            reader->update(this);        }    }private:    list<observer *> oblist; };  //定义具体的 观察者,读者class reader: public observer{public:    reader(){}    virtual ~reader(){}//拉模型    virtual void update(subject * sub){        cout<<getName()<<"正在浏览的内容是:"<<sub->getContent()<<endl;    }//推模型    virtual void update(string content){        cout<<getName()<<"正在浏览的内容是:"<<content<<endl;    }        string getName(){return m_name;}    void setName(string name){m_name = name;}private:    string m_name; };  //定义具体的指标,推送新闻信息class newspaper:public subject{public:    newspaper(){};    virtual ~newspaper(){} //设置内容    virtual int setContent(string content){        m_content = content;        notifyAllobserver(); //默认是拉模型,就想给你推送一个摘要一样        return 1;    }//失去具体内容 -- 用于推模型    virtual string getContent(){        return m_content;    }//失去摘要 -- 用于拉模型     virtual string getSummary(){         return "摘要";     }  private:    string m_content;};   int main(int argc,char *argv[]){     //定义报纸主题    newspaper *subject = new newspaper();     //定义读者    reader * r1 = new reader();    r1->setName("adele");     reader * r2 = new reader();    r2->setName("Bob");     reader * r3 = new reader();    r3->setName("ceilina");      //设置内容        //报纸开始退出订阅者    subject->attach(r1);    subject->setContent("明天多云");    cout << "\n----------富丽的分割线 \n"<<endl;         subject->attach(r2);    subject->setContent("明天晴天");    cout << "\n----------富丽的分割线 \n"<<endl;        subject->attach(r3);    subject->setContent("over");         cout<<"-------end-----\n";      return 0;} 

成果

作者:小魔童哪吒