c++设计模式

一、设计模式的六大设计原则

  • 单一职责原则:就一个类而言,应该仅有一个引起它变化的原因。
  • 开放封闭原则:软件实体可以扩展,但是不可修改。即面对需求,对程序的改动可以通过增加代码来完成,但是不能改动现有的代码。
  • 里氏代换原则:一个软件实体如果使用的是一个基类,那么一个适用于其派生类。即在软件中,把基类替换成派生类,程序的行为没有变化。
  • 依赖倒转原则:抽象不应该依赖细节,细节应该依赖抽象。即针对接口编程,不要对实现编程。
  • 迪米特原则:如果两个类不直接通信,那么这两个类就不应当发生直接的相互作用。如果一个类需要调用另一个类的某个方法的话,可以通过第三个类转发这个调用。
  • 接口隔离原则:每个接口中不存在派生类用不到却必须实现的方法,如果不然,就要将接口拆分,使用多个隔离的接口。

二、设计模式的种类

设计模式分三类

  • 创造型模式:单例模式、工厂模式、建造者模式、原型模式
  • 结构型模式:适配器模式、桥接模式、外观模式、组合模式、装饰模式、享元模式、代理模式
  • 行为型模式:责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式

常见的设计模式:

  • 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
  • 工厂模式:包括简单工厂模式、抽象工厂模式、工厂方法模式
    • 简单工厂模式:主要用于创建对象。用一个工厂来根据输入的条件产生不同的类,然后根据不同类的虚函数得到不同的结果。
    • 工厂方法模式:修正了简单工厂模式汇总不遵循开放封闭原则。把选择判断移动到了客户端去实现,如果想要添加新功能就不同修改原来的类,直接修改客户端即可。
    • 抽象工厂模式:定义了一个创建一系列相关或相互依赖的接口,而无需指定他们的具体类。
  • 观察者模式:定义了一种一对多的关系,让多个观察对象同时监听一个主题对象,主题对象发生变化时,会通知所有的观察者,使他们能够更新自己。
  • 装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成派生类更为灵活。

三、单例模式

  • 单例模式:保证类的实例化对象仅有一个,并且提供一个访问他的全局访问点。

  • 应用场景

    • 表示文件系统的类,一个操作系统一定是只有一个文件系统,因此文件系统的类的实例有且仅有一个。
    • 打印机打印程序的实例,一台计算机可以连接好几台打印机,但是计算机上的打印程序只有一个,就可以通过单例模式来避免两个打印作业同时输出到打印机。
  • 实现方式
    单例模式可以通过全局或者静态变量的形式实现,这样比较简单,但是这样会影响封装性,难以保证别的代码不会对全局变量造成影响。

    • 默认的构造函数、拷贝构造函数、赋值构造函数声明为私有的,这样禁止在类的外部创建该对象;
    • 全局访问点也要定义成 静态类型的成员函数,没有参数,返回该类的指针类型。因为使用实例化对象的时候是通过类直接调用该函数,并不是先创建一个该类的对象,通过对象调用。
  • 分类:

    • 懒汉模式:直到第一次用到类的实例时才去实例化,上面是懒汉实现。
    • 饿汉模式:类定义的时候就实例化。
  • 懒汉模式不安全的实现方式:
    原因:考虑当两个线程同时调用 getinstance 方法,并且同时检测到 instance 是 NULL,两个线程会同时实例化对象,不符合单例模式的要求。

    class Singleton{
    private:
      static Singleton * instance;
      Singleton(){}
      Singleton(const Singleton& tmp){}
      Singleton& operator=(const Singleton& tmp){}
    public:
      static Singleton* getInstance(){
          if(instance == NULL){
              instance = new Singleton();
          }
          return instance;
      }
    };
    Singleton* Singleton::instance = NULL;
  • 线程安全的懒汉模式实现:
    方法:加锁
    存在的问题:每次判断实例对象是否为空,都要被锁定,如果是多线程的话,就会造成大量线程阻塞。

    #include <iostream>
    #include <pthread.h>
    using namespace std;
    class singleInstance{
    public:
      static singleInstance* GetsingleInstance(){
          if (instance == NULL){
              pthread_mutex_t mutex;//mutex mlock; 加锁互斥
              pthread_mutex_lock(&mutex);//mlock.lock();
              if (instance == NULL){
                  instance = new singleInstance();
              }
              pthread_mutex_unlock(&mutex);//mlock.unlock();
          }
          return instance;
      };
      ~singleInstance(){};
    private:// 涉及创建对象的函数都设置为private
      singleInstance(){};
      singleInstance(const singleInstance& other){};
      singleInstance& operator=(const singleInstance& other){ return *this; };
      static singleInstance* instance;
    };
    //懒汉式
    singleInstance* singleInstance::instance = nullptr;
    int main(){
      // 因为没有办法创建对象,就得采用静态成员函数的方法返回静态成员变量
      singleInstance *s = singleInstance::GetsingleInstance();
      //singleInstance *s1 = new singleInstance(); // 报错
         cout << "Hello World";
         return 0;
    }

    方法:内部静态变量,在全局访问点getInstance中定义静态实例。

    class Singleton{
    private:
      static pthread_mutex_t mutex;
      Singleton(){
          pthread_mutex_init(&mutex, NULL);
      }
      Singleton(const Singleton& temp){}
      Singleton& operator=(const Singleton& temp){}
    public:
      static Singleton* getInstence(){ 
          static Singleton instence;
          return &instence;
      }
    };
    pthread_mutex_t Singleton::mutex; 

-饿汉模式的实现:
饿汉模式本身就是线程安全的不用加锁。

#include <iostream>
#include <pthread.h>
using namespace std;
class singleInstance{
public:
    static singleInstance* GetsingleInstance(){ // 饿汉式,直接创建一个对象,不需要加锁
        static singleInstance instance;
        return &instance;
    };
    ~singleInstance(){};
private:// 涉及创建对象的函数都设置为private
    singleInstance(){};
    singleInstance(const singleInstance& other){};
    singleInstance& operator=(const singleInstance& other){ return *this; };
};
int main(){
    // 因为没有办法创建对象,就得采用静态成员函数的方法返回
    singleInstance *s = singleInstance::GetsingleInstance();
    //singleInstance *s1 = new singleInstance(); // 报错
       cout << "Hello World";
       return 0;
}
全部评论

相关推荐

02-25 19:38
门头沟学院 Java
点赞 评论 收藏
分享
今天 16:40
已编辑
门头沟学院 C++
26学院本太难了,很多公司机筛就给我刷了。机会都难拿到如果是简历存在问题也欢迎拷打————————————————————分割线——————————————————————2026.3.4更新:发完贴之后,时不时投递又收到了不少的笔试/面试邀请。主要是之前投递简历出去之后基本上都是沉默状态,年后好转了不少timeline:2026.01.21&nbsp;文远知行笔试,半年多没刷算法题&nbsp;-&gt;挂&nbsp;(后续HR说春招可以重新安排笔试)2026.2.4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;小鹏汇天&nbsp;技术一面,第二周收到结果&nbsp;-&gt;挂2026.2.12&nbsp;&nbsp;&nbsp;大众Cariad代招&nbsp;技术二面&nbsp;-&gt;Offer2026.2.28&nbsp;&nbsp;&nbsp;多益网络技术面试,由于风评太差,一直在犹豫要不要接面试&nbsp;-&gt;推迟-----------分割线-----------2026.3&nbsp;月前的某一天,临时去电网报名了二批计算机岗位的笔试2026.3.6&nbsp;从上家公司实习离职,氛围最好的一家公司,leader&nbsp;说可以帮忙转正,但是流程太长,而且我们部门据说只有一个&nbsp;hc,更想要研究生,我很有可能是会被签外包公司在这里干活,就离职了。2026.3.9&nbsp;入职新公司,大众Cariad&nbsp;以外部公司的身份进组,项目组签了三年,后续三年应该都可以在这里呆,不知道有没有希望原地跳槽。2026.3.10&nbsp;电网考试居然说我通过资格审查了,短信约我去参加资格审查,请假一天,买了&nbsp;12&nbsp;号晚上的机票回成都2026.3.15&nbsp;参加国家电网计算机类笔试2026.3.17&nbsp;电网出成绩了,感觉很低。觉得已经🈚️了2026.3.18&nbsp;收到电网面试通知,通知&nbsp;3.22-3.25&nbsp;这个时间去面试,我的岗位只招&nbsp;1&nbsp;个人。据说面试只有&nbsp;2-3&nbsp;人,不知道能不能成功----------分割线-----------2026.3.21&nbsp;电网面试结束,感觉回答的还勉勉强强,大概是2个岗位分别招1个人,一共11人面试,实际来了9人2026.3.27&nbsp;出面试成绩,满分100分,早上10:20左右发现面试成绩46,我震惊了,没截图,后面过了十分钟重新看发现面试成绩给我改成58了。但同样震惊。朋友问我是不是把面试官打了,哈哈
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务