• 设计模式


    GOF - 23 模式分类

    从目的来看:

    •  创建型:将对象的部分创建工作延迟到子类或者其他对象,从而应对需求变化为对象创建时具体类型实现引来的冲击;
    • 结构型:通过类继承或者对象组合获得更灵活的结构,从而应对需求变化为对象的结构带来的冲击;
    • 行为型:通过类继承或者对象组合来划分类与对象间的职责,从而应对需求变化为多个交互的对象带来的冲击;

    从范围来看:

    • 类模式处理类与子类的静态关系。
    • 对象模式处理对象间的动态关系。

    从封装变化角度对模式分类

    重构获得模式

    • 面向对象设计模式是“好的面向对象设计”,所谓好是指可 “应对变化,提高复用”;
    • 现代软件设计的特征:需求的频繁变化。设计模式的要点就是“寻找变化点”,然后在变化处应用设计模式,从而更好应对需求变化。“什么时候,什么地点应用设计模式”比“理解设计模式结构本身”更为重要。
    • 设计模式的应用不宜先入为主,一上来就使用设计模式是对设计模式的最大误用。没有一步到位的设计模式。

    重构关键技法

    • 静态 —> 动态
    • 早绑定 ——> 晚绑定
    • 继承 ——> 组合
    • 编译时依赖 ——> 运行时依赖
    • 紧耦合 ——> 松耦合

    “组件协作”模式

    • 现代软件专业分工之后的第一个结果是“框架与应用程序的划 分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之 间的松耦合,是二者之间协作时常用的模式。

    典型模式

            • Template Method

       • Observer / Event

       • Strategy

    Template Method 模式


     动机(Motivation)

    • 在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。
    • 如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求?

     结构化软件设计流程

     

     第一种情况,库开发人员开发1、3、5三个步骤,应用程序开发人员开发2、4步骤及主流程(程序框架),示例如下:

     1 //程序库开发人员
     2 class Library{
     3 
     4 public:
     5     void Step1(){
     6         //...
     7     }
     8 
     9     void Step3(){
    10         //...
    11     }
    12 
    13     void Step5(){
    14         //...
    15     }
    16 };
    template1_lib.cpp
     1 //应用程序开发人员
     2 class Application{
     3 public:
     4     bool Step2(){
     5         //...
     6     }
     7 
     8     void Step4(){
     9         //...
    10     }
    11 };
    12 
    13 int main()
    14 {
    15     Library lib();
    16     Application app();
    17 
    18     lib.Step1();
    19 
    20     if (app.Step2()){
    21         lib.Step3();
    22     }
    23 
    24     for (int i = 0; i < 4; i++){
    25         app.Step4();
    26     }
    27 
    28     lib.Step5();
    29 
    30 }
    template1_app.cpp

    面向对象软件设计流程

    第二种情况,程序库开发人员开发1、3、5以及程序框架(稳定),应用程序开发人员开发2、4。步骤2、4易发生变化,程序库开发人员没法决定其内容,所以先声明2、4为纯虚函数,由继承的子类来重写2、4方法。

     1 //程序库开发人员
     2 class Library{
     3 public:
     4     //稳定 template method
     5     void Run(){
     6         
     7         Step1();
     8 
     9         if (Step2()) { //支持变化 ==> 虚函数的多态调用
    10             Step3(); 
    11         }
    12 
    13         for (int i = 0; i < 4; i++){
    14             Step4(); //支持变化 ==> 虚函数的多态调用
    15         }
    16 
    17         Step5();
    18 
    19     }
    20     //基类的虚构函数要声明为虚函数的原因
    21     //在实现多态时,当基类操作派生类,在析构时防止只析构基类而不析构派生类
    22     virtual ~Library(){ }
    23 
    24 protected:
    25     
    26     void Step1() { //稳定
    27         //.....
    28     }
    29     void Step3() {//稳定
    30         //.....
    31     }
    32     void Step5() { //稳定
    33         //.....
    34     }
    35 
    36     virtual bool Step2() = 0;//变化
    37     virtual void Step4() =0; //变化
    38 };
    template2_lib.cpp
     1 //应用程序开发人员
     2 class Application : public Library {
     3 protected:
     4     virtual bool Step2(){
     5         //... 子类重写实现
     6     }
     7 
     8     virtual void Step4() {
     9         //... 子类重写实现
    10     }
    11 };
    12 
    13 int main()
    14     {
    15         Library* pLib=new Application();  //pLib为多态指针
    16         lib->Run();
    17 
    18         delete pLib;
    19     }
    20 }
    template2_app.cpp

    以上两种情况体现为早晚绑定的关系,情况一,结构化设计,应用程序调用程序库,为早绑定,C语言主要都是这种设计;

    情况二,面向对象设计,Libray虽然也写的早,但是会调用写得晚的应用程序的内容,即晚绑定。

     模式定义

    •  定义一个操作中的算法的骨架 (稳定) ,而将一些步骤延迟 (变化) 到子类中。 Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override 重写)该算法的 某些特定步骤。 ——《 设计模式》 GoF

     Template Method即模板方法,也就是第二情况的设计,算法的结构即Run()方法,可重定义的特定步骤即2、4步骤。

    在Library中,稳定的算法Run()写成非虚函数,支持变化的部分写成虚函数;

    注意:

      设计模式最大的作用就是在稳定与变化之间找到隔离点,然后分离它们,进而管理变化。对于极端的情况,软件所有部分都在变化,那么就所有设计模式都失效,若所有部分都是稳定的,设计模式也没存在的意义。所以在模式应用时,要分辨出软件结构中哪些是相对稳定的,变化的

     结构

     要点总结

    • Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性) 为很多应用程序框架提供了灵活的扩展点(继承+多态),是代码复用方面的基本实现结构。
    • 除了可以灵活应对子步骤的变化外, “不要调用我,让我来调用你” 的反向控制结构是Template Method的典型应用。
    • 在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将它们设置为protected方法。

    参考:https://github.com/liu-jianhao/Cpp-Design-Patterns/

  • 相关阅读:
    转:imageNamed和dataWithContentsOfFile的区别
    [内存管理实践 之 1]在返回按钮中,释放内存
    转:当程序崩溃的时候怎么办 Part2
    iOS 内存管理,我们需要一套切实可行的实践指导书,而不是理论指导书
    转 iOS程序中调用系统自带应用(短信,邮件,浏览器,地图,appstore,拨打电话)
    iOS笔记:内存管理
    转:【图文教程】创建Xcode自定义模板
    判断两个数的大小,返回其中的大者/小者
    iOS全局变量与属性的内存管理
    UIImage 详解
  • 原文地址:https://www.cnblogs.com/y4247464/p/14196862.html
Copyright © 2020-2023  润新知