Python实现设计模式--05.建造者模式(Builder Pattern)

建造者模式是一种创建类的模式,它尽可能的保证代码的复用性,而且可读性也非常好(最终产生对象的过程对调用方是透明的)。

很多朋友应该都做过微信公众号或者支付宝服务窗的消息推送,下面是微信公众平台给的消息示例:

{
    "touser":"OPENID",
    "template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",
    "url":"http://weixin.qq.com/download",
    "miniprogram":{
        "appid":"xiaochengxuappid12345",
        "pagepath":"index?foo=bar"
    },
    "data":{
        "first":{
            "value":"恭喜你购买成功!",
            "color":"#173177"
        },
        "keynote1":{
            "value":"巧克力",
            "color":"#173177"
        },
        "keynote2":{
            "value":"39.8元",
            "color":"#173177"
        },
        "keynote3":{
            "value":"2014年9月22日",
            "color":"#173177"
        },
        "remark":{
            "value":"欢迎再次购买!",
            "color":"#173177"
        }
    }
}

具体参数可在公众平台开发者文档查看。现在的问题是如何设计消息模版呢?我身边有的同事是用字符串替换,有的对各个模版建立一个类,这里我不往深里讨论方案对优劣,本节结束后读者们可以尝试做下对比。下面我给出一种建造者模式的做法,创建builder类如下(简便起见,去掉了miniprogram参数):

# -*- coding: utf-8 -*-

from collections import OrderedDict
import json


# 模版中“data”节点的各个元素的数据结构
class Metadata:
    def __init__(self, value, color):
        self.value = value
        self.color = color


# 微信消息的建造器
class MessageBuilder:
    __contentDict = OrderedDict()  # 定义整个模版的数据结构,保持添加的顺序
    __dataDict = OrderedDict()  # 定义data节点的数据结构,保持添加的顺序
    __dataNoteNext = 1  # data节点要添加的下一个元素的序号

    def __init__(self, touser, template_id, url):
        self.__contentDict['touser'] = touser
        self.__contentDict['template_id'] = template_id
        self.__contentDict['url'] = url
        self.__contentDict['data'] = self.__dataDict

    def add_first_data(self, value, color):
        data = Metadata(value, color)
        self.__dataDict['first'] = data
        return self

    def add_remark_data(self, value, color):
        data = Metadata(value, color)
        self.__dataDict['remark'] = data
        return self

    def add_note_data(self, value, color):
        data = Metadata(value, color)
        self.__dataDict['keynote' + str(self.__dataNoteNext)] = data
        self.__dataNoteNext += 1
        return self

    def build(self):
        # 为打印出来看的方便,这里将json序列化后的结果缩进2个空格,并且不把中文转为unicode
        return json.dumps(self.__contentDict, default=lambda o: o.__dict__, indent=2, ensure_ascii=False)
有两点要说明下:

  • 建造者内部的字典采用OrderedDict,是为了保持顺序与微信示例一致
  • 建造者每个方法都返回了本对象的引用,这是一个很常用的技巧

建造者有了,下面我们来生成两条消息。前几天我在丰巢快递柜寄了票件,下图是我收到的其中两个微信通知:

Python实现设计模式--05.建造者模式(Builder Pattern)_第1张图片  Python实现设计模式--05.建造者模式(Builder Pattern)_第2张图片

我们模拟作如上两条微信消息:

if __name__ == '__main__':
    order_builder = MessageBuilder('user111111', 'template_id_order', '') \
        .add_first_data('您的寄件订单已经生成啦!请打包好您的包裹前往柜机投递。', '#173177') \
        .add_note_data('03226580', '#173177') \
        .add_note_data('10(小格);14(中格);18(大格);', '#173177') \
        .add_note_data('顺丰速运', '#173177') \
        .add_remark_data('“一分钱寄全国”优惠券以放入到你的账户,在柜机支付时记得使用哦。', '#173177')
    print('生成下单通知微信消息')
    print(order_builder.build())


    print()


    send_builder = MessageBuilder('user222222', 'template_id_send', 'http://balabala') \
        .add_first_data('丰巢已收到您的包裹,并已通知快递员来收取啦!', '#173177') \
        .add_note_data('顺丰速运', '#173177') \
        .add_note_data('422154541545', '#173177') \
        .add_note_data('某地址某地址某地址某地址', '#173177') \
        .add_note_data('2017-07-31 11:20', '#173177') \
        .add_remark_data('点击详情查看物流进度', '#173177')
    print('生成投递微信消息')
    print(send_builder.build())
运行结果:
生成下单通知微信消息
{
  "touser": "user111111",
  "template_id": "template_id_order",
  "url": "",
  "data": {
    "first": {
      "color": "#173177",
      "value": "您的寄件订单已经生成啦!请打包好您的包裹前往柜机投递。"
    },
    "keynote1": {
      "color": "#173177",
      "value": "03226580"
    },
    "keynote2": {
      "color": "#173177",
      "value": "10(小格);14(中格);18(大格);"
    },
    "keynote3": {
      "color": "#173177",
      "value": "顺丰速运"
    },
    "remark": {
      "color": "#173177",
      "value": "“一分钱寄全国”优惠券以放入到你的账户,在柜机支付时记得使用哦。"
    }
  }
}

生成投递微信消息
{
  "touser": "user222222",
  "template_id": "template_id_send",
  "url": "http://balabala",
  "data": {
    "first": {
      "color": "#173177",
      "value": "丰巢已收到您的包裹,并已通知快递员来收取啦!"
    },
    "keynote1": {
      "color": "#173177",
      "value": "顺丰速运"
    },
    "keynote2": {
      "color": "#173177",
      "value": "422154541545"
    },
    "keynote3": {
      "color": "#173177",
      "value": "某地址某地址某地址某地址"
    },
    "remark": {
      "color": "#173177",
      "value": "点击详情查看物流进度"
    },
    "keynote4": {
      "color": "#173177",
      "value": "2017-07-31 11:20"
    }
  }
}

本人经验,这类情形下,建造者模式使得代码更加清晰易懂,读者有没有一点点启发呢?

你可能感兴趣的:(设计模式-python)