• c++模板模式


    模板模式

    什么是模板模式

    模板模式(Template Method Pattern)是一种行为设计模式,它定义了一个操作中的算法骨架,将某些步骤的具体实现延迟到子类中。模板模式使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤,从而实现代码复用和扩展性。

    使用场景包括:

    存在一组相似的操作:当有一组操作拥有相同的算法结构,但是某些步骤的实现细节各不相同的时候,可以使用模板模式来定义这些操作的通用部分,并将变化的部分留给子类去实现。
    
    算法结构固定,部分步骤可变:如果你希望在不改变算法整体结构的前提下,允许子类自由地扩展或修改某些步骤,模板模式是个很好的选择。这样可以保证算法的主体逻辑一致,同时提供必要的定制化能力。
    
    封装算法细节:当需要将算法的实现细节封装起来,仅暴露一个高层接口给调用者使用时,模板模式可以帮助隐藏复杂的内部实现,提高代码的可读性和维护性。
    
    代码复用和扩展:如果你发现有很多重复的代码,只是其中某些小部分逻辑不同,可以考虑使用模板模式提取公共部分到父类中,通过子类化来实现差异化的部分。
    

    示例应用:

    UI框架中的渲染流程,如所有页面都有加载、渲染内容、处理事件的基本流程,但具体的内容渲染逻辑由各个页面子类实现。
    数据库访问框架中,可能有一个通用的数据库操作流程(连接数据库、发送查询、处理结果、关闭连接),而具体查询的SQL语句则由子类提供。
    在框架或库的开发中,如Java并发包中的AbstractQueuedSynchronizer(AQS)使用模板方法模式定义了获取和释放锁的模板方法,具体实现留给子类(如ReentrantLock)。
    

    为什么使用模板模式

    抽象类中统一操作步骤,并规定好接口,让子类实现接口。这样可以把各个具体的, 子类和操作步骤解耦合。你只希望客户端扩展某个特定算法步骤,而不是整个算法或其结构时,可使用模板方法模式。当多个类的算法除一些细微不同之外几乎完全一样时, 你可使用该模式。但其后果就是,只要算法发生变化, 你就可能需要修改所有的类。

    模板模式实现步骤

    1.提供一个抽象类:负责规定好接口,让子类实现接口,定义一个模板方法

    2.提供具体实现子类:实现抽象类的抽象接口即可
    在这里插入图片描述

    示例

    #include 
    
    // 抽象基类,定义模板方法和基本操作
    class CoffeeMaker {
    public:
        virtual ~CoffeeMaker() {}
        // 模板方法:冲泡咖啡的步骤
        void brewCoffee() {
            boilWater();
            brew();
            pourInCup();
            if (customerWantsCondiments()) {
                addCondiments();
            }
        }
    
    protected:
        // 基本操作,留给子类实现
        virtual void brew() = 0;
        virtual void addCondiments() = 0;
    
        // 可能不需要子类重写的辅助方法
        void boilWater() {
            std::cout << "Boiling water" << std::endl;
        }
        void pourInCup() {
            std::cout << "Pouring into cup" << std::endl;
        }
    
        // 可能需要子类决定的策略方法
        virtual bool customerWantsCondiments() {
            return true;
        }
    };
    
    // 具体子类:黑咖啡
    class BlackCoffee : public CoffeeMaker {
    protected:
        void brew() override {
            std::cout << "Brewing black coffee" << std::endl;
        }
        void addCondiments() override {
            // 黑咖啡不加调料
        }
    };
    
    // 具体子类:加糖加奶咖啡
    class SugarMilkCoffee : public CoffeeMaker {
    protected:
        void brew() override {
            std::cout << "Brewing coffee with sugar and milk" << std::endl;
        }
        void addCondiments() override {
            std::cout << "Adding sugar and milk" << std::endl;
        }
        bool customerWantsCondiments() override {
            return true;
        }
    };
    
    int main() {
        CoffeeMaker* maker = new BlackCoffee();
        maker->brewCoffee();
        delete maker;
    
        std::cout << "\n";
    
        maker = new SugarMilkCoffee();
        maker->brewCoffee();
        delete maker;
    
        return 0;
    }
    

    在这个例子中,CoffeeMaker类是抽象基类,它定义了冲泡咖啡的基本步骤作为模板方法(brewCoffee),并声明了两个纯虚函数brew和addCondiments作为基本操作,让子类去实现。BlackCoffee和SugarMilkCoffee是具体子类,它们实现了不同的冲泡方式和添加调料的逻辑。通过这种方式,我们可以复用通用的冲泡流程,同时允许子类灵活地改变某些步骤,符合模板方法模式的设计理念。

    模板模式优缺点

    优点

    • 你可仅允许客户端重写一个大型算法中的特定部分, 使得算法其他部分修改对其所造成的影响减小
    • 你可将重复代码提取到一个超类中

    缺点

    • 部分客户端可能会受到算法框架的限制
    • 通过子类抑制默认步骤实现可能会导致违反里氏替换原则
    • 模板方法中的步骤越多, 其维护工作就可能会越困难
  • 相关阅读:
    100道Java高频面试题(阿里面试官整理)
    迭代器-面试
    【SpringBoot笔记23】SpringBoot中RedisTemplate对象及其常用方法的使用
    突破众多技术干货的迷茫
    STM32L4R9ZIY6PTR STM32L4高性能嵌入式—MCU
    面试官:用Java如何设计阻塞队列,再说说ArrayBlocking和LinkedBlocking
    使用 Alacritty 替代 Gnome-Terminal 解决 Ubuntu 中终端的行间距问题
    SPSS统计教程:卡方检验
    视觉SLAM十四讲:从理论到实践(Chapter5:相机与图像)
    图像分割 - Hough变换圆环检测
  • 原文地址:https://blog.csdn.net/weixin_45672157/article/details/139727271