设计模式总结

本文深入探讨设计模式的本质,从起源、作用到解决的关键问题,详细阐述设计原则如开闭原则、单一职责等。通过模板方法、观察者、策略、单例、工厂等模式实例,揭示设计模式如何提升代码质量并实现灵活扩展。同时,介绍了抽象工厂、责任链、装饰器、组合及代理模式,帮助开发者掌握软件设计的核心技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、设计模式是什么

  • 设计模式是指在软件开发中,经过验证的,用于解决在特定环境下,重复出现的,特定问题的解决方案。
  • 解决问题的固定套路。
  • 慎用设计模式。

二、设计模式是怎么来的

  • 满足设计原则后,慢慢迭代出来的。

三、设计模式解决了什么问题

  • 前提:具体需求既有稳定点,又有变化点
  • 期望修改少量的代码,就可以适应需求的变化。
  • 比喻:整洁的房间,好动的猫,怎么保证房间的整洁 → 把猫关在一个笼子里。

四、设计原则

  • 开闭原则
    • 一个类应该对扩展开放对修改关闭
    • 通过继承组合的方式进行扩展。
    • 与开闭原则相关的原则:单一职责、里氏替换、接口隔离。
  • 单一职责:一个类应该仅有一个引起它变化的原因。
  • 里氏替换
    • 子类方法重写父类方法时,需要实现父类方法的职责,避免之前调用父类方法的地方出错。
    • 场景:多态中虚函数重写。
    • 目标:约束扩展中的继承(对扩展开放)。
  • 接口隔离
    • 不应该强迫客户依赖它们不用的方法,使用 publicprotectedprivate
    • 一个类对另一个类的依赖应该建立在最小的接口上。
  • 迪米特原则(最小知道原则)
    • 一个对象应该对其他对象保持最小的了解。
    • 目标:形成高内聚低耦合的系统。
      • 相近的功能应该放在同一个类中,不相近的不要放在同一个类中。
      • 类与类之间的依赖关系要简单清晰,依赖越少越好。
    • 要求:
      • 不该有直接依赖关系的类之间不要有依赖。
        class NetWork {
                 
        public: 
            int Write(int fd, unsigned char* buf, size_t sz);
            int Read(int fd, unsigned char* buf, size_t sz);
            // int Write(HTTP* pHttp); 耦合度太高
        };
        
        class HTTP {
                 
        private:
            NetWork* pNet;
        }; 
        
      • 有依赖关系的类之间,尽量只依赖必要的接口。
        class IEncode {
                 
        public:
            unsigned char* encode(HTTP* p) = 0;
        };
        class IDecode {
                 
        public:
            json* decode(HTTP* p) = 0;
        };
        
        class A : public IEncode, IDecode {
                 
        public:
            unsigned char* encode(HTTP* p);
            json* decode(HTTP* p);
        };
        
        class B : public IEncode {
                 };
        class C : public IDecode {
                 };
        
  • 依赖倒置
    • 目标:高内聚、低耦合。
    • 高层模块不应该依赖低层模块,两者都应该依赖抽象。
    • 抽象不应该依赖具体实现,具体实现应该依赖抽象。
    • 抽象确定稳定点。
    • 用户使用和代码实现的解耦,也就是接口的使用者不依赖具体的实现。在这里插入图片描述
  • 组合优于继承:继承的耦合度高。

五、设计模式学习步骤

  • 该设计模式解决了什么问题 → 稳定点变化点
  • 该设计模式的代码结构是什么。
  • 该设计模式符合哪些设计原则。
  • 如何在该设计模式上扩展代码。
  • 该设计模式有哪些典型应用场景。

六、模板方法

  • 解决的问题:
    • 稳定点:算法的骨架。
    • 变化点:子流程需要变化。
  • 符合哪些设计原则:
    • 单一职责:只暴露算法的骨架接口,其它的子流程接口都用 protectedprivate 封装起来。
    • 开闭原则:不能改变算法的骨架,只能修改子流程。
    • 依赖倒置。
      • 子类扩展时,需要依赖基类的虚函数实现。
      • 使用者只依赖接口。
    • 封装变化点:变化的地方通过 protected 暴露给子类去扩展。
    • 接口隔离:通过 protectedprivate 隔离接口。
    • 最小知道原则:对于用户而言,只需要知道算法的骨架接口即可。
  • 如何扩展:
    • 实现子类继承基类,复写子流程。
    • 通过多态调用方式使用。
  • 代码结构:
    • 基类中有骨架流程接口。
    • 所有子流程对子类开放(protected)并且是虚函数。
    • 通过多态调用方式使用。
      // 背景:某个动物园,有一套固定的表演流程,但是其中若干个表演子流程可替换,以迭代更新表演流程。
      /*
       *  接口隔离原则:1、类封装,使用权限限定词来实现。 2、类与类依赖,使用接口实现(依赖注入)
       *  最小知道原则
       *  单一职责原则:类封装
       *  开闭原则:对扩展开放,对修改关闭
       *  里氏替换原则:多态
       *
       *  扩展方式:继承、多态组合
       */
      
      using namespace std;
      
      class ZooShow {
             
      public:
          void Show() {
             
              if (Show0()) {
             
                  PlayGame();
              }
              Show1();
              Show2();
              Show3();
          }
      
      private:
          void PlayGame() {
             
              cout << "after Show0, then play game" << endl;
          }
      // 对其它用户关闭,但是对子类开放
      protected:
          bool expired;
          virtual bool Show0() {
             
              cout << "Show0" << endl;
              if (!expired) {
             
                  return true;
              }
              return false;
          }
          virtual void Show1() {
             
              cout << "Show1" << endl;
          }
          virtual void Show2() {
             
              cout << "Show2" << endl;
          }
          virtual void Show3() {
             
              cout << "Show3" << endl;
          }
      };
      
      // 模板方法
      class ZooShowEx1: public ZooShow {
             
      protected:
          virtual bool Show0()  {
             
              cout << "Show0 Ex1" << endl;
              if (!expired) {
              // 里氏替换原则
                  return true;
              }
              return false;
          }
      };
      
      class ZooShowEx2: public ZooShow {
             
      protected:
          virtual void Show2() {
             
              cout << "Show2 E2" << endl;
          }
      };
      
      class ZooShowEx3: public ZooShow {
             
      protected:
          virtual bool Show0() {
             
              cout << "Show0 Ex3" << endl;
              if (!expired) {
             
                  return true;
              }
              return false;
          }
          virtual void Show2() {
             
              cout << "Show2 Ex3" << endl;
          }
      };
      
      int main() {
             
          std::cout << "Template Method!" << std::endl;
      
          // 第一次迭代
          ZooShow * zs1 = new ZooShowEx1; // 晚绑定
          zs1->Show();
      
          // 第二次迭代
          ZooShow * zs2 = new ZooShowEx2;
          zs2->Show();
      
          // 第三次迭代
           ZooShow * zs3 = new ZooShowEx3;
           zs3->Show();
      
          return 0;
      }
      

七、观察者模式

  • 解决的问题:
    • 稳定点:“一” 对 “多” 的依赖关系,“一” 变化,“多” 跟着变化。
    • 变化点:“多” 增加、“多” 减少。
  • 符合哪些设计原则:
    • 面向接口编程。
      • 不将变量类型声明为某个特定的具体类,而是声明为某个接口。
      • 用户程序无需获知对象的具体类型,只需要知道对象所具有的接口。
      • 减少系统中各部分的依赖关系,从而实现高内聚、低耦合的类型设计方案。
    • 接口隔离:类与类的依赖建立在一个接口上。
      • 容器存储接口。
      • 依赖注入。
    • 封装变化点:通过 AttachDetach 接口来封装变化点。
  • 如何扩展:
    • 继承实现接口。
    • 调用 AttachDetach
  • 代码结构:
    • 实现观察接口。
    • 多个观察者类实现。
    • 客户类通过容器组合基类指针。
    • 通过依赖注入增加或者删除观察对象。
      // 背景:气象站发布气象资料给数据中心,数据中心经过处理,将气象信息更新到三个不同的显示终端
      // "一" 指的是数据中心,"多" 指的是不同的显示终端
      
      using namespace std;
      // 观察接口
      class IDisplay {
             
      public:
          virtual void Show(float temperature) = 0;
          virtual ~IDisplay() {
             }
      };
      // 观察者类
      class DisplayA: public IDisplay {
             
      public:
          virtual void Show(float temperature) {
             
              cout << "DisplayA show" << endl;
          }
      };
      class DisplayB: public IDisplay {
             
      public:
          virtual void Show(float temperature) {
             
              cout << "DisplayB show" << endl;
          }
      };
      
      class DisplayC: public IDisplay {
             
          virtual void Show(float temperature) {
             
              cout << "DisplayC show" << endl;
          }
      };
      
      class DataCenter {
             
      public:
      	// 依赖注入
          void Attach(IDisplay * ob) {
             
              obs.push_back(ob);
          }
          // 依赖注入
          void Detach(IDisplay * ob) {
             
              obs.remove(ob);
          }
      
          void notify() {
             
              float temperature = CalcTemperature();
              for (auto ob : obs) {
             
                  ob->Show(temperature);
              }
          }
      
      private:
          float 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值