第三课 模板方法(Template Method)

        >> 什么时候、什么地点应用设计模式,比理解设计结构本身更为重要;

        >> 设计模式的应用不宜先入为主,没有一步到位的设计模式,敏捷开发中提倡“Reafactoring to Patterns(重构到模式)”;

一. 动机

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

>> 如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化晚期实现需求?

二. 样例

        程序库开发人员和应用程序开发人员分别开发某些功能,版本一:

// 程序库开发人员
class Library{
public:
    void Step1(){ // ... }
    void Step3(){ // ... }
    void Step5(){ // ... }
};
// 应用程序开发人员
class Application{
public:
    bool Step2(){ // ... }
    bool Step4(){ // ... }
};

int main()
{
    Library lib();
    Application app();

    lib.Step1();
    
    if(app.Step2()){
        lib.Step3();
    }

    for(int i = 0; i < 4; i++){
        app.Step4();
    }

    lib.Step5();
}

版本二:

// 程序库开发人员
class Library{
public:
    virtual ~Library(){}

    // 稳定 template method
    void Run(){
        Step1();
        if(Step2()){    // 支持变化 ==> 虚函数的多态调用
            Step3();
        }
        
        for(int i = 0; i < 4; i++){
            Step4();    // 支持变化 ==> 虚函数的多态调用
        }

        Step5();
    }

protected:
    void Step1(){ // ... }    // 稳定
    void Step3(){ // ... }    // 稳定
    void Step5(){ // ... }    // 稳定

    virtual bool Step2() = 0; // 变化
    virtual bool Step4() = 0; // 变化
};
// 应用程序开发人员
class Application : public Library{
protected:
    virtual bool Step2(){ // ... 子类重写实现}
    virtual bool Step4(){ // ... 子类重写实现}
};

int main()
{
    Library* pLib = new Application ();
    pLib->Run();
    
    delete pLib;
}

        将两个版本以图示方法展示,版本一如下:

        版本二如下:

        版本一的调用关系是Application调用Library,这是一种早绑定的写法(因为Library一定是先于Application出现的,一个晚出现的调用一个早出现的,就是早绑定,这是c语言中主流的做法);而版本二中,通过虚函数,实现了Library调用Application,从而达到了晚绑定的目的(这是面向对象语言的特征)。

三. 要点总结

>> Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性),为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构;

>> 除了可以灵活应对子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是Template Method的典型应用;

>> 在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将它们设为protected方法;

以下是微信小程序通过第三方服务实现定时发送模板消息的代码示例: 1. 在小程序中调用第三方服务提供商的API,将需要发送的模板消息发送到第三方服务提供商的服务器上: ```javascript wx.request({ url: 'https://third-party.com/send_template_msg', method: 'POST', data: { openid: 'xxxxxxxxxxxxxxxxxxxx', template_id: 'xxxxxxxxxxxxxxxxxxxx', data: { keyword1: { value: '模板消息内容' }, keyword2: { value: '模板消息内容' }, // ... }, // 发送时间,格式为时间戳(秒) send_time: 1609459200, }, success: function(res) { console.log('发送成功'); }, fail: function(res) { console.log('发送失败'); } }) ``` 2. 在第三方服务提供商的服务器上实现定时发送功能,将消息发送给指定用户: ```python import time import requests # 发送模板消息 def send_template_msg(openid, template_id, data): url = 'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN' headers = {'Content-Type': 'application/json'} params = { 'touser': openid, 'template_id': template_id, 'data': data } res = requests.post(url, headers=headers, json=params).json() if res['errcode'] == 0: print('发送成功') else: print('发送失败') # 定时发送消息 def schedule_send(): # 获取待发送消息列表 msg_list = get_msg_list() # 遍历待发送消息列表 for msg in msg_list: # 获取当前时间戳 now_timestamp = int(time.time()) # 如果当前时间戳大于等于消息的发送时间戳,则发送消息 if now_timestamp >= msg['send_time']: send_template_msg(msg['openid'], msg['template_id'], msg['data']) # 将消息从待发送列表中删除 delete_msg(msg['id']) ``` 3. 在小程序中查询发送记录,调用第三方服务提供商提供的API: ```javascript wx.request({ url: 'https://third-party.com/get_send_record', method: 'GET', data: { openid: 'xxxxxxxxxxxxxxxxxxxx', start_time: 1609459200, end_time: 1609545600, }, success: function(res) { console.log(res.data); }, fail: function(res) { console.log('查询失败'); } }) ``` 以上代码仅供参考,实际使用时需要根据具体业务需求进行修改和完善。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值