《设计模式的艺术》笔记 - 模板方法模式

介绍

模板方法模式定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。模板方法模式是一种类行为模式。

实现

myclass.h

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include <iostream>
#include <unordered_map>
#include <atomic>
#include <vector>
#include <memory>

class Abstract {    // 抽象基类
public:
    void templateMethod();  // 模板方法
    virtual void primitiveOperation1(); // 基本操作1
    virtual void primitiveOperation2(); // 基本操作2
    virtual void primitiveOperation3(); // 基本操作3
};

class Concrete : public Abstract {  // 具体子类,重写基本操作方法
public:
    void primitiveOperation1() override;

    void primitiveOperation2() override;

    void primitiveOperation3() override;
};

#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"
#include <thread>
#include <unistd.h>
#include <sstream>

void Abstract::primitiveOperation1() {
    std::cout << "默认基本操作1" << std::endl;
}

void Abstract::primitiveOperation2() {
    std::cout << "默认基本操作2" << std::endl;
}

void Abstract::primitiveOperation3() {
    std::cout << "默认基本操作3" << std::endl;
}

void Abstract::templateMethod() {
    primitiveOperation1();
    primitiveOperation2();
    primitiveOperation3();
}

void Concrete::primitiveOperation1() {
    std::cout << "重写基本操作1" << std::endl;
}

void Concrete::primitiveOperation2() {
    std::cout << "重写基本操作2" << std::endl;
}

void Concrete::primitiveOperation3() {
    std::cout << "重写基本操作3" << std::endl;
}

main.cpp

cpp 复制代码
#include <iostream>
#include <mutex>
#include "myclass.h"

int main() {
    Abstract *abstract = new Concrete();
    abstract->templateMethod();
    delete abstract;

    return 0;
}

总结

优点

  1. 模板方法模式在父类中形式化地定义一个算法,而由它的子类来实现细节的处理。在子类实现详细的处理算法时并不会改变算法中步骤的执行次序。

  2. 模板方法模式是一种代码复用技术,它在类库设计中尤为重要。它提取了类库中的公共行为,将公共行为放在父类中,而通过其子类来实现不同的行为。它鼓励恰当使用继承来实现代码复用。

  3. 模板方法模式可实现一种反向控制结构。通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行。

  4. 在模板方法模式中可以通过子类来覆盖父类的基本方法,不同的子类可以提供基本方法的不同实现,更换和增加新的子类很方便,符合单一职责原则和开闭原则。

缺点

  1. 需要为每一个基本方法的不同实现提供一个子类。如果父类中可变的基本方法太多,将会导致类的个数增加,系统更加庞大,设计也更加抽象。此时,可结合桥接模式来进行设计。

适用场景

  1. 对一些复杂的算法进行分割,将其算法中固定不变的部分设计为模板方法和父类具体方法,而一些可以改变的细节由其子类来实现。即一次性地实现一个算法的不变部分,并将可变的行为留给子类来实现。

  2. 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。

  3. 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。

练习

myclass.h

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include <iostream>
#include <unordered_map>
#include <atomic>
#include <vector>
#include <memory>

class DatabaseOperator {    // 抽象基类
public:
    void operation(const std::string &sql, bool update = false);  // 模板方法
    virtual void connect() = 0; // 连接数据库
    virtual void open() = 0; // 打开数据库
    virtual void query(const std::string &sql) = 0; // 查询数据库
    virtual void update(const std::string &sql) = 0; // 更新数据库
    virtual void close() = 0; // 关闭数据库
};

class JDBCBridgeODBC : public DatabaseOperator {  // 具体子类,重写基本操作方法
public:
    void connect() override;

    void open() override;

    void query(const std::string &sql) override;

    void update(const std::string &sql) override;

    void close() override;
};

class ManufacturerDriver : public DatabaseOperator { // 具体子类,重写基本操作方法
public:
    void connect() override;

    void open() override;

    void query(const std::string &sql) override;

    void update(const std::string &sql) override;

    void close() override;
};

class ThreadPool : public DatabaseOperator {    // 具体子类,重写基本操作方法
public:
    void connect() override;

    void open() override;

    void query(const std::string &sql) override;

    void update(const std::string &sql) override;

    void close() override;
};

#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

cpp 复制代码
//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"
#include <thread>
#include <unistd.h>
#include <sstream>

void DatabaseOperator::operation(const std::string &sql, bool update) {
    connect();
    open();
    if (update) {
        this->update(sql);
    } else {
        query(sql);
    }
    this->close();
}

void JDBCBridgeODBC::connect() {
    std::cout << "JDBC-ODBC桥接方式连接数据库" << std::endl;
}

void JDBCBridgeODBC::open() {
    std::cout << "JDBC-ODBC桥接方式打开数据库" << std::endl;
}

void JDBCBridgeODBC::query(const std::string &sql) {
    std::cout << "JDBC-ODBC桥接方式查询数据库" << sql << std::endl;
}

void JDBCBridgeODBC::update(const std::string &sql) {
    std::cout << "JDBC-ODBC桥接方式更新数据库" << sql << std::endl;
}

void JDBCBridgeODBC::close() {
    std::cout << "JDBC-ODBC桥接方式关闭数据库" << std::endl;
}

void ManufacturerDriver::connect() {
    std::cout << "厂商驱动方式连接数据库" << std::endl;
}

void ManufacturerDriver::open() {
    std::cout << "厂商驱动方式打开数据库" << std::endl;
}

void ManufacturerDriver::query(const std::string &sql) {
    std::cout << "厂商驱动方式查询数据库" << sql << std::endl;
}

void ManufacturerDriver::update(const std::string &sql) {
    std::cout << "厂商驱动方式更新数据库" << sql << std::endl;
}

void ManufacturerDriver::close() {
    std::cout << "厂商驱动方式关闭数据库" << std::endl;
}

void ThreadPool::connect() {
    std::cout << "线程池方式连接数据库" << std::endl;
}

void ThreadPool::open() {
    std::cout << "线程池方式打开数据库" << std::endl;
}

void ThreadPool::query(const std::string &sql) {
    std::cout << "线程池方式查询数据库" << sql << std::endl;
}

void ThreadPool::update(const std::string &sql) {
    std::cout << "线程池方式更新数据库" << sql << std::endl;
}

void ThreadPool::close() {
    std::cout << "线程池方式关闭数据库" << std::endl;
}

main.cpp

cpp 复制代码
#include <iostream>
#include <mutex>
#include "myclass.h"

int main() {
    DatabaseOperator *jdbc = new JDBCBridgeODBC();
    jdbc->operation("select * from t", false);
    jdbc->operation("drop table t", false);
    delete jdbc;

    return 0;
}
相关推荐
密码小丑1 小时前
11月4日(内网横向移动(一))
笔记
暗黑起源喵2 小时前
设计模式-工厂设计模式
java·开发语言·设计模式
鸭鸭梨吖2 小时前
产品经理笔记
笔记·产品经理
齐 飞2 小时前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
丫头,冲鸭!!!3 小时前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
听忆.3 小时前
手机屏幕上进行OCR识别方案
笔记
Selina K4 小时前
shell脚本知识点记录
笔记·shell
4 小时前
开源竞争-数据驱动成长-11/05-大专生的思考
人工智能·笔记·学习·算法·机器学习
霍格沃兹测试开发学社测试人社区5 小时前
软件测试学习笔记丨Flask操作数据库-数据库和表的管理
软件测试·笔记·测试开发·学习·flask
幸运超级加倍~5 小时前
软件设计师-上午题-16 算法(4-5分)
笔记·算法