关于c++:设计模式之单例工厂发布订阅者模式设计模式

28次阅读

共计 5782 个字符,预计需要花费 15 分钟才能阅读完成。

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

单例模式

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

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

利用场景:

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;
}
 

成果

作者:小魔童哪吒

正文完
 0