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

来源:互联网 发布:ipad电视直播软件 编辑:程序博客网 时间:2024/05/07 22:35

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

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

背景

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

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

还有下面的事件推送消息

这里写图片描述

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

这里写图片描述

反例

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

这里写图片描述

上面的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.

微信公众平开开发文档

0 0
原创粉丝点击