近段时间兵长在开发一个小项目,需要用到设计模式的思想,但是兵长苦于没有接触过设计模式,于是走到胖sir座位旁边
兵长:侧目撇了一眼胖sir,故作淡定的说道,诶,设计模式,我想我身边应该有人用过设计模式吧
胖sir抬头看看了旁边这位大兄弟,又马上低头鼓捣自己的手机,还是手机有趣
兵长:看着胖sir默不作声的样子,心中有些着急。于是直接对胖sir说,胖sir,你要是能给我讲讲基本的设计模式,我一会带你上分
胖sir淡定的推了推眼镜,说道:不就是上分嘛,有啥了不起的
兵长:悄悄告诉你,我是星耀~
胖sir:我给你说说基本的单例模式,工程模式以及发布订阅模式,你要带我5连胜才行~
保证一个类仅有一个实例,并提供一个该实例的全局访问点
在软件系统中,经常有这样一些特殊的类,必须保证他们 在系统中只存在一个实例,才能确保它们的逻辑正确性, 以及良好的效率
DBPool 、读取配置文件
#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();
}
胖sir:简单吧,兵长,来我再给你说说工厂模式
#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;
}
胖sir:那你要再带我赢一把
发布订阅模式和观察者模式是同一个东西吗?NONONO
目标对象主动向观察者推送目标的详细信息,不 管观察者是否需要,推送的信息通常是目标对象的全部或 部分数据,相当于广播通信。
目标对象在通知观察者的时候,只传递少量的信 息。如果观察者需要更具体的信息,由观察者主动到目标 对象中获取,相当于是观察者从目标对象中拉数据。一般 这种模型的实现中,会把目标对象通过update方法传递给 观察者,这样在观察者需要获取数据的时候,就可以通过 这个引用来获取了。
公众号通知,淘宝通知,知乎通知,微信通知等等。
//观察者模式,需要弄明白 何为观察者,何为目标
//以我们用手机看报纸为例, 我们 是观察者, 报纸是目标
//接下来我们来模拟一下观察者模式
#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;
}
效果
img
胖sir:都记下了吧,先带我上分,一会你再复习一下
作者:小魔童哪吒