• 作者:老汪软件技巧
  • 发表时间:2024-10-15 17:04
  • 浏览量:

虽然我已经好久没更新技术博客,但我并没有放弃技术博客更新的意思。

今晚(2024年10月14日)翻到四年前看李建忠老师设计模式视频时记下的笔记,感觉笔记记得还算不错。既然已经有了初始素材,我便想着将这些素材做些整理后分享出来。

阅读这些笔记时,有些不懂之处我重新去看了视频,发现已经懂得老师意思。这种感受到自己进步的喜悦,更增加我的分享欲望。

于是有此系列,我给它起名叫做“我将4年前的设计模式笔记再看一遍”。

一、模式总结

组件协作模式分类,通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。

这是李建忠老师所讲的第一个设计模式,他认为这是面向对象设计中,最基础且应用最广的一个设计模式。

一开始,我认为Template Method应该是一个很高大上的东西,听过老师的讲解,再结合自己敲过的代码,发现确实基础,且应用许多。且先将讲解示例,从我的脑子中,搬到这里来。

1、原始实现

如下代码,有一个库中实现了3个方法,到一个具体应用中,实现了另外2个方法,待到主程序中的时候,一直使用固有的顺序调用。

以下代码所举示例,来源于Windows画窗口(之前学习OpenGL的时候,需要先复制粘贴一套画窗口的流程),main函数中的调用步骤是稳定的,Library中的内容也稳定,变化的只是Application中的实现。

class Library{
    void step1() {}
    void step3() {}
    void step5() {}
};
class Application{
    void step2() {}
    void step4() {}
};
int main(){
    Library lib;
    Application app;
    
    lib.step1();
    
    if(lib.step3()){
        app.step2();
    }
    
    for(int i=0; i<4; ++i){
        app.step4();
    }
    
    lib.step5();
    
    return 0;
}

2、改进实现

可以看到,因为调用顺序是稳定的,于是将step2和step4两个方法,作为虚函数,挪到Library中,将整个稳定的调用顺序也挪到Library中。step2和step4供Application实现。

step2和step4使用protected的原因是,他们两个对于Library来说,调用是没有意义的,不提供给外部是最好的。

不过,当这样设计完成之后,作为只写Application部分的人来说,就只知道step2与step4了,并不了解整个调用流程是怎样的,会存在一些问题:最明显示例是,对我来说,虽然知道怎么写服务器逻辑,但是对于底层的调用、实现,其实是不明就里的。

class Library{
    void step1() {}
    void step3() {}
    void step5() {}
    
    void run(){
        step1();
    
        if(step3()){
            step2();
        }
    
        for(int i=0; i<4; ++i){
            step4();
        }
    
        step5();
    }
    
protected:
    virtual void step2() = 0;
    virtual void step4() = 0;
};
class Applicationpublic Library{
    virtual void step2() {}
    virtual void step4() {}
};
int main(){
    Application app;
 // 四年后来看,此处依然很帅,只关注主流程,这对于理解业务需求来说,会快许多
    app.run();
    return 0;
}

二、项目应用

听完整个设计模式的讲解之后,想到,目前我们项目中,用到这个模式的地方是真的多。Library有我写的,有不是我写的。

就服务器代码,对于一个Service来说,当我们继承了Service基类,并且将它注册到全局Service管理模块之后,并不知道它是如何跑起来的。只需要继承(重写)某几个特定方法,你的逻辑就会在对的时机跑起来。

客户端,在世界聊天和好友聊天的设计的时候,为了少写代码,我提取了公用部分出来,作为两个界面的基类(即Library),完成收到服务器消息 -- 筛选 -- 展示结果这一套流程,但两个界面有自己不同的展示结果函数(Library中的step2和step4)。

Unity3D引擎,脚本中的Update、OnStart这些方法,其实也是Template Method的体现,Update作为Library的一个虚函数,被整体调用框架调用,写逻辑的我只需要在Update中写点东西,就会每一帧被调用到。

三、感想、记录节点

1、心理变化,今天(2020-7-5)下午睡完午觉后,彼时脑袋昏沉,知道自己需要学习,但是不想学习,于是打开YouTube,继续听这一课。

听的前期,想着再坚持一会会儿,就看看其他娱乐视频吧。没想到,慢慢地,被老师所讲的内容所吸引,竟然40分钟的一节课,很快就听完,并且有了共鸣。于是立马进行记录。

2、听C++ 版的设计模式,对于C++语言的熟练程度,也是有所帮助的。比如虚函数说到底,也是一个函数指针,这就意味着,函数指针是很重要的。

3、老师讲解的过程中有提到,其实模式并不是一敲代码就拿出来用的,往往是在重构之后,才发现,重构的结果,往往就对应了某一(几)种模式。

4、花半小时对40分钟的课程进行了总结、记录。感觉自己有点类似于金庸武侠小说《侠客行》中的石破天,知道怎么出招打人,但却不知道招数名称。(这说的是我当年的状态,即已经用过“模板方法”很多次,却不知道它叫“模板方法”。)