身边的设计模式--策略模式

设计模式这么高端的东西一直不敢写,因为有很多牛人的博客已经写的很好了,所以就把自己平时用到的设计模式分享一下。

我要分享的第一个设计模式不是单例,而是策略模式。

背景

在微信公众号开发中,开发者要对用户发过了的消息进行处理。用户发过来的消息有很多种,给用户回复的消息也有很多种,这个时候就需要根据业务需求进行处理。
先来看一下用户可以发过来的消息类型

文本消息
图片消息
语音消息
视频消息
小视频消息
地理位置消息
链接消息

还有下面的事件推送消息

这里写图片描述

再来看一下可以给用户回复的消息类型

这里写图片描述

反例

针对用户发过来的消息进行回复,刚开始的设计是这个样子的。

这里写图片描述

上面的if语句有130多行。可维护性差。

策略模式

这里写图片描述

公众号中的策略模式

这里写图片描述

代码实现

回复消息基类

MessageService.java

import java.util.Map;

/**
 * 微信公众号回复消息
 * 
 * @author 程高伟
 *
 * @date 2016年6月29日 上午10:40:49
 */
public abstract class MessageService {
    /**
     * 消息请求体
     */
    protected Map<String, String> requestContent;

    /**
     * 发送方openId
     */
    protected String toUserName;
    /**
     * 接收方openId
     */
    protected String fromUserName;
    /**
     * 消息创建时间
     */
    protected long createTime;
    /**
     * 消息类型
     */
    protected String msgType;
    /**
     * 消息编号
     */
    protected String msgId;

    /**
     * 构造函数,将请求放进构造函数中
     * 
     * @param requestContent
     */
    public MessageService(Map<String, String> requestContent) {
        this.requestContent = requestContent;

        // 发送方帐号(UserName)
        fromUserName = requestContent.get("FromUserName");
        // 公众帐号
        toUserName = requestContent.get("ToUserName");
        // 时间戳
        createTime = Long.parseLong(requestContent.get("CreateTime"));
        // 消息类型
        msgType = requestContent.get("MsgType");
        // 消息id
        msgId = requestContent.get("MsgId");
    }

    /**
     * 处理不同类型的消息,然后返回结果
     * 
     * @return 返回消息响应
     */
    public abstract String response();
}

消息上下文

MessageContext.java


/**
 * 消息上下文
 * 
 * @author 程高伟
 *
 * @date 2016年6月29日 上午10:53:30
 */
public class MessageContext {
    private MessageService service;

    public MessageContext(MessageService service) {
        this.service = service;
    }

    public String response() {
        return this.service.response();
    }
}

回复文本消息

TextMessageService.java

import java.util.Map;

/**
 * 回复文本消息
 * 
 * @author 程高伟
 *
 * @date 2016年6月28日 下午10:24:40
 */
public class TextMessageService extends MessageService {

    /**
     * 文本消息的消息内容
     */
    private String content;

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public TextMessageService(Map<String, String> requestContent) {
        super(requestContent);
        this.setContent(requestContent.get("Content"));
    }

    @Override
    public String response() {
        /*<xml>
            <ToUserName><![CDATA[toUser]]></ToUserName>
            <FromUserName><![CDATA[fromUser]]></FromUserName>
            <CreateTime>12345678</CreateTime>
            <MsgType><![CDATA[text]]></MsgType>
            <Content><![CDATA[你好]]></Content>
          </xml>
        */
        // 这里是用户发什么就回复什么
        TextMessage textMessage = new TextMessage();
        textMessage.setToUserName(fromUserName);
        textMessage.setFromUserName(toUserName);
        textMessage.setCreateTime(System.currentTimeMillis());
        textMessage.setMsgType(MessageUtil.MESSAGE_TEXT);
        textMessage.setContent(this.getContent());
        return MessageUtil.textMessageToXml(textMessage);

    }

}

回复图片消息

ImageMessageService.java


import java.util.Map;


/**
 * 回复图片消息
 * 
 * @author 程高伟
 *
 * @date 2016年6月28日 下午10:26:32
 */
public class ImageMessageService extends MessageService {

    private String picUrl;
    private String mediaId;

    public String getPicUrl() {
        return picUrl;
    }

    public void setPicUrl(String picUrl) {
        this.picUrl = picUrl;
    }

    public String getMediaId() {
        return mediaId;
    }

    public void setMediaId(String mediaId) {
        this.mediaId = mediaId;
    }

    public ImageMessageService(Map<String, String> requestContent) {
        super(requestContent);
        this.setPicUrl(requestContent.get("PicUrl"));
        this.setMediaId(requestContent.get("MediaId"));
    }

    @Override
    public String response() {
        /*<xml>
            <ToUserName><![CDATA[toUser]]></ToUserName>
            <FromUserName><![CDATA[fromUser]]></FromUserName>
            <CreateTime>12345678</CreateTime>
            <MsgType><![CDATA[image]]></MsgType>
            <Image>
                <MediaId><![CDATA[media_id]]></MediaId>
            </Image>
          </xml>
         */
        // 发什么图片就回复什么图片
        ImageMessage imageMessage = new ImageMessage();
        imageMessage.setToUserName(fromUserName);
        imageMessage.setFromUserName(toUserName);
        imageMessage.setCreateTime(System.currentTimeMillis());
        imageMessage.setMsgType(MessageUtil.MESSAtGE_IMAGE);
        Image image = new Image();
        image.setMediaId(mediaId);
        imageMessage.setImage(image);
        return MessageUtil.imageMessageToXml(imageMessage);

    }

}

回复图文消息

NewsMessageService.java



import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * 回复图文消息
 * 
 * @author 程高伟
 *
 * @date 2016年6月28日 下午10:26:32
 */
public class NewsMessageService extends MessageService {

    public NewsMessageService(Map<String, String> requestContent) {
        super(requestContent);
        // 微信会给用户回复图文消息,用户不会给微信发图文消息
    }

    @Override
    public String response() {
        // 构造图文列表
        Article article = new Article();
        article.setTitle("程高伟的博客");
        article.setUrl("http://blog.csdn.net/frankcheng5143");
        article.setPicUrl("http://avatar.csdn.net/E/B/6/1_frankcheng5143.jpg");
        article.setDescription("通技术之脉络,集框架之精华,开源,分享,我在路上!");
        Article article1 = new Article();
        article1.setTitle("慕课网");
        article1.setUrl("http://www.imooc.com/");
        article1.setPicUrl(
                "https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=278743832,3927440098&fm=58&s=06E6DD16CCB109825DF431C601007031");
        article1.setDescription(
                "慕课网(IMOOC)是国内最大的IT技能学习平台。慕课网(IMOOC)提供了丰富的移动端开发、php开发、web前端、android开发以及html5等视频教程资源公开课。");
        List<Article> newsList = new ArrayList<>();
        newsList.add(article);
        newsList.add(article1);
        // 封装图文消息
        NewsMessage newsMessage = new NewsMessage();
        newsMessage.setToUserName(fromUserName);
        newsMessage.setFromUserName(toUserName);
        newsMessage.setCreateTime(System.currentTimeMillis());
        newsMessage.setMsgType(MessageUtil.MESSAGE_NEWS);
        newsMessage.setArticles(newsList);
        newsMessage.setArticleCount(newsList.size());
        return MessageUtil.newsMessageToXml(newsMessage);

    }

}

修改后的处理类

    public String processRequest(HttpServletRequest request) {
        Map<String, String> requestMap = MessageUtil.xmlToMap(request);
        logger.info("----------用户发来的消息:{}----------", requestMap);
        String response = "";
        MessageContext context;
        // 消息类型
        String msgType = requestMap.get("MsgType");
        if (StringUtils.equals(msgType, MessageUtil.MESSAGE_TEXT)) {// 文本消息
            context = new MessageContext(new TextMessageService(requestMap));
            response = context.response();
        } else if(StringUtils.equals(msgType, MessageUtil.MESSAtGE_IMAGE)){// 图片消息
            context = new MessageContext(new ImageMessageService(requestMap));
            response = context.response();
        }else if(StringUtils.equals(msgType, MessageUtil.MESSAGE_EVENT)){// 点击按钮
            context = new MessageContext(new NewsMessageService(requestMap));
            response = context.response();
        }else {
            // 微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。
            // 假如服务器无法保证在五秒内处理并回复,可以直接回复空串,
            // 微信服务器不会对此作任何处理,并且不会发起重试。
            // 推荐方式 直接回复success
            response = "success";
        }
        return response;
    }

策略模式

策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。

三个角色:

  • 环境(Context)角色:持有一个Strategy的引用。
  • 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。 
  • 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。

参考文献

阎宏. Java与模式[M]. 电子工业出版社, 2002.

微信公众平开开发文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值