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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 保证一个类仅有一个实例,并提供一个该实例的全局访问点

设计模式

单例模式

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

   在软件系统中,经常有这样一些特殊的类,必须保证他们 在系统中只存在一个实例,才能确保它们的逻辑正确性, 以及良好的效率

应用场景:

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

c++

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

效果

image.png

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

发布订阅模式和观察者模式是同一个东西吗?  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;
}

效果

image.png

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

image.png

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~

相关文章
|
2月前
|
设计模式 前端开发 搜索推荐
前端必须掌握的设计模式——模板模式
模板模式(Template Pattern)是一种行为型设计模式,父类定义固定流程和步骤顺序,子类通过继承并重写特定方法实现具体步骤。适用于具有固定结构或流程的场景,如组装汽车、包装礼物等。举例来说,公司年会节目征集时,蜘蛛侠定义了歌曲的四个步骤:前奏、主歌、副歌、结尾。金刚狼和绿巨人根据此模板设计各自的表演内容。通过抽象类定义通用逻辑,子类实现个性化行为,从而减少重复代码。模板模式还支持钩子方法,允许跳过某些步骤,增加灵活性。
137 11
|
24天前
|
设计模式
「全网最细 + 实战源码案例」设计模式——模式扩展(配置工厂)
该设计通过配置文件和反射机制动态选择具体工厂,减少硬编码依赖,提升系统灵活性和扩展性。配置文件解耦、反射创建对象,新增产品族无需修改客户端代码。示例中,`CoffeeFactory`类加载配置文件并使用反射生成咖啡对象,客户端调用时只需指定名称即可获取对应产品实例。
86 40
|
25天前
|
设计模式 关系型数据库
「全网最细 + 实战源码案例」设计模式——简单工厂模式
简单工厂模式是一种创建型设计模式,通过工厂类根据传入参数创建不同类型的对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。适用于对象种类较少且调用者无需关心创建细节的场景。
53 19
|
23天前
|
设计模式 Java
「全网最细 + 实战源码案例」设计模式——生成器模式
生成器模式(Builder Pattern)是一种创建型设计模式,用于分步骤构建复杂对象。它允许用户通过控制对象构造的过程,定制对象的组成部分,而无需直接实例化细节。该模式特别适合构建具有多种配置的复杂对象。其结构包括抽象建造者、具体建造者、指挥者和产品角色。适用于需要创建复杂对象且对象由多个部分组成、构造过程需对外隐藏或分离表示与构造的场景。优点在于更好的控制、代码复用和解耦性;缺点是增加复杂性和不适合简单对象。实现时需定义建造者接口、具体建造者类、指挥者类及产品类。链式调用是常见应用方式之一。
50 12
|
25天前
|
设计模式 关系型数据库
「全网最细 + 实战源码案例」设计模式——工厂方法模式
简单工厂模式是一种创建型设计模式,通过一个工厂类根据传入参数创建不同类型的产品对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。适用于创建对象种类较少且调用者无需关心创建细节的场景。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。
44 15
|
26天前
|
设计模式 缓存 安全
「全网最细 + 实战源码案例」设计模式——单例设计模式
单例模式是一种创建型设计模式,确保一个类在整个程序运行期间只有一个实例,并提供一个全局访问点来获取该实例。它常用于控制共享资源的访问,如数据库连接、配置管理等。实现方式包括饿汉式(类加载时初始化)、懒汉式(延迟加载)、双重检查锁、静态内部类和枚举单例等。其中,枚举单例最简单且安全,能有效防止反射和序列化破坏。
35 7
|
3月前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
57 2
|
3月前
|
设计模式 安全 Java
Kotlin - 改良设计模式 - 构建者模式
Kotlin - 改良设计模式 - 构建者模式
|
3月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
63 1
|
3月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式

热门文章

最新文章