[设计模式]行为模式-模板方法(C++描述)

本文介绍了模板方法设计模式的概念及其实现方式,并通过C++代码示例详细解释了其结构和应用场景,最后总结了该模式的优点和局限性。

 [设计模式]行为模式-模板方法(C++描述)

second60 20180504

1. 什么是模板方法

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

简单地说:完成一件事情,有些步骤相同,有些步骤不相同,在父类中定义模板方法,写好具体流程,但具体的实现是在子类中。

2. 模板方法结构图

分析:

模板方法类:实现了模板方法,定义了算法的骨架

具体实现类:定现抽象类中的抽象方法,即算法骨架中的步骤

代码:

#include <iostream>
using namespace std;

// 1. 抽象类:定义算法的骨架
class Beverage {
public:
    // 模板方法:算法的骨架,不能被子类改变
    void makeBeverage() {
        boilWater();
        brew();          // 子类实现
        pourInCup();
        addCondiments(); // 子类实现
    }
    
    // 公共方法(所有子类一样)
    void boilWater() {
        cout << "烧水至100度" << endl;
    }
    
    void pourInCup() {
        cout << "倒入杯中" << endl;
    }
    
    // 抽象方法:子类必须实现
    virtual void brew() = 0;          // 冲泡
    virtual void addCondiments() = 0; // 加调料
};

// 2. 具体子类:实现具体步骤
class Coffee : public Beverage {
public:
    void brew() override {
        cout << "冲泡咖啡粉" << endl;
    }
    void addCondiments() override {
        cout << "加糖和牛奶" << endl;
    }
};

class Tea : public Beverage {
public:
    void brew() override {
        cout << "冲泡茶叶" << endl;
    }
    void addCondiments() override {
        cout << "加柠檬" << endl;
    }
};

// 3. 使用
int main() {
    cout << "=== 制作咖啡 ===" << endl;
    Beverage* coffee = new Coffee();
    coffee->makeBeverage();  // 调用模板方法
    
    cout << "\n=== 制作茶 ===" << endl;
    Beverage* tea = new Tea();
    tea->makeBeverage();
    
    delete coffee;
    delete tea;
    return 0;
}

2.1 优点

1. 定义了算法的骨架,实现延迟到子类中

2. 模板方法是一种代码复用的技术,提取了公共的行为

3. 是一种反向控制的结构,通过父类调用子类的具体实现。

4. 通过子类对父类,扩展新的行业,符合开闭原则。

2.2 缺点

1. 每种实现都会有新的子类,类的个数增加,系统变得庞大

3 适用场景

1. 某业务或算法中有固定的步骤,且步骤中具有可变的逻辑来实现不同的算法。

2. 适用于某抽象类中,子类公共的逻辑,即把子类公共逻辑提取到父类中。

3. 适用于反转控制逻辑,即父类调用子类的方法。

4 例子

举个棋牌类的例子:如棋牌中有很多麻将,麻将的结算有一个固定的流程:基本番结算,别加番结算,其他结算,总结算。那么可以写成模版方法。

分析:

1. 定义一个麻将结算模版抽象类 MahjongFan

2. 不同地方麻将总体流程是一致的,但结算方法是不一致的。

#include <iostream>
using namespace std;

// 1. 抽象类:定义算番算法的骨架
class MahjongFan {
public:
    MahjongFan() : FanNum(0), FanMultiple(1) {}  // 初始化
    
    virtual ~MahjongFan() {}  // 虚析构
    
    // 模板方法:固定的算番流程
    int compute() {
        basicFan();     // 基本番
        specialFan();   // 特殊番
        otherFan();     // 其他番
        return countAll();  // 汇总计算
    }
    
    // 抽象方法:子类必须实现
    virtual void basicFan() = 0;
    virtual void specialFan() = 0;
    virtual void otherFan() = 0;
    virtual int countAll() = 0;

protected:
    int FanNum;       // 番数
    int FanMultiple;  // 番倍数
};

// 2. 济南麻将算番(具体实现)
class JiNanMahjongFan : public MahjongFan {
public:
    JiNanMahjongFan(int baseShip = 1, int mingLou = 1, int piao = 1) 
        : _baseShip(baseShip), _mingLou(mingLou), _piao(piao) {}
    
    void basicFan() override {
        FanNum = 1;  // 济南麻将基本番
        cout << "济南麻将基本番: 1" << endl;
    }
    
    void specialFan() override {
        FanNum += 2;  // 济南麻将特殊番
        cout << "济南麻将特殊番: +2" << endl;
    }
    
    void otherFan() override {
        FanNum += 1;  // 济南麻将其他番
        cout << "济南麻将其他番: +1" << endl;
    }
    
    int countAll() override {
        // 济南麻将结算公式
        int count = _baseShip * FanNum * _mingLou * _piao;
        cout << "济南麻将总番数: " << FanNum 
             << ", 结算分: " << count << endl;
        return count;
    }

private:
    int _baseShip;   // 底注
    int _mingLou;    // 明楼倍数
    int _piao;       // 飘倍数
};

// 3. 四川麻将算番(另一个具体实现)
class SiChuanMahjongFan : public MahjongFan {
public:
    SiChuanMahjongFan(int baseShip = 1, int queMen = 1) 
        : _baseShip(baseShip), _queMen(queMen) {}
    
    void basicFan() override {
        FanNum = 2;  // 四川麻将基本番
        cout << "四川麻将基本番: 2" << endl;
    }
    
    void specialFan() override {
        FanNum += 3;  // 四川麻将特殊番(缺一门等)
        cout << "四川麻将特殊番: +3" << endl;
    }
    
    void otherFan() override {
        FanNum += 0;  // 四川麻将无其他番
        cout << "四川麻将其他番: +0" << endl;
    }
    
    int countAll() override {
        // 四川麻将结算公式(不同)
        int count = _baseShip * FanNum * _queMen;
        cout << "四川麻将总番数: " << FanNum 
             << ", 结算分: " << count << endl;
        return count;
    }

private:
    int _baseShip;   // 底注
    int _queMen;     // 缺门倍数
};

// 4. 使用示例
int main() {
    cout << "===== 济南麻将 =====" << endl;
    MahjongFan* jinanFan = new JiNanMahjongFan(10, 2, 1);
    int result1 = jinanFan->compute();  // 调用模板方法
    cout << "最终得分: " << result1 << endl;
    
    cout << "\n===== 四川麻将 =====" << endl;
    MahjongFan* sichuanFan = new SiChuanMahjongFan(5, 2);
    int result2 = sichuanFan->compute();
    cout << "最终得分: " << result2 << endl;
    
    delete jinanFan;
    delete sichuanFan;
    return 0;
}

上面对于济南麻将是一种结算,对于一百种麻将,可能会有一百种不同结算,而且每个地方都有自已的特殊的算法。通过模版方法,每个地方,只需增加一个类并实现即可。使算法类做单一职责,同时各个地方算法互不影响,使用时,只需使用具体地方的算番类即可

MahjongFan*  jinanFan = new JiNanMahjongFan();

jinanFan->compute();

4 总结

  模板方法类,符合单一职责和开放关闭原则,是一种比较好的行为实现方法。把父类的调用实现延迟到子类中实现,从而使父类具有统一的接口,但却有不同的实现。有良好的扩展性,但通常适用于固定步骤,且步骤可变的算法或业务中。

5 后语

今天终于讲到设计模式中的行为模式,相对于创建和结构模式,行为模式用途更多,品种也更多。每种设计模式都是为了解决某些问题而产生的。同时一个问题,也可能由多种模式都可解决。具体使用哪种,看实现需求而定。学以致用,我也会把用过的或可以用到某项目的分享出来。分享也是一种乐趣。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值