简单工厂模式
简单工厂模式:的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了和具体产品的依赖。
上面的这句话怎么理解呢?我们看看下面这段代码,这段代码是客户端的业务逻辑代码:
// 文本消息
if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
return buildTextMsgXml(requestMap);
}
// 图片消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {
respContent = "/:p-(您发送的是图片消息!暂时处理不了哎!";
}
// 地理位置消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {
respContent = "/:p-(您发送的是地理位置消息!暂时处理不了哎!";
}
// 链接消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {
respContent = "/:p-(您发送的是链接消息!暂时处理不了哎!";
}
// 音频消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {
espContent = "/:p-(您发送的是音频消息!暂时处理不了哎!";
}
//....还有许多
这段代码是客户端的代码,很多刚开始写代码的朋友都会和我一样,用大堆的条件控制语句完成业务逻辑代码,但是这样有一个问题,如果新增了一个“消息”类型,那么我们是不是就要在客户端新增加一个if语句呢?这样写当然是没有错误的,但是它增加了代码的“Bad Smell(代码的坏味道) ”,而且增加了客户端的维护成本,也不符合软件设计的“开闭原则”。
代码如何改进,那么我们不妨采用一种简单工厂方法来消除客户端的维护成本。
首先定义一个消息处理接口:
/*
* @(#)MessageHandler.java 2014-3-16
*/
package com.lotus.weixin.reqhandler;
import java.util.Map;
/**
* 消息处理接口
* @author tsface
* @version 2014-3-16
* @since 1.0
*/
public interface MessageHandler
{
/**
* 生成消息的类型
* @param megType
* @return
*/
public String buildXMlStr(Map<String, String> requestMap);
}
不同消息处理类实现消息处理接口,下一个代码片段是文本消息的实现
/*
* @(#)TextMsgHandlerImpl.java 2014-3-16
*/
package com.lotus.weixin.reqhandler.impl;
import java.util.Date;
import java.util.Map;
import com.avatar.gdk.util.StringUtils;
import com.lotus.weixin.message.resp.TextMessage;
import com.lotus.weixin.message.utils.MessageUtil;
import com.lotus.weixin.reqhandler.MessageHandler;
/**
* 文本消息处理类
* @author tsface
* @version 2014-3-16
* @since 1.0
* @see
*/
public class TextMsgHandlerImpl implements MessageHandler
{
@Override
public String buildXMlStr(Map<String, String> requestMap)
{
// 发送方帐号(open_id)
String fromUserName = requestMap.get("FromUserName");
String toUserName = requestMap.get("ToUserName");
// 消息类型
String reqContent = requestMap.get("Content");
// 回复文本消息
TextMessage textMessage = new TextMessage();
textMessage.setToUserName(fromUserName);
textMessage.setFromUserName(toUserName);
textMessage.setCreateTime(new Date().getTime());
textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
textMessage.setFuncFlag(0);
if(StringUtils.isNotEmpty(reqContent) )
{
if("?".equals(reqContent))
{
textMessage.setContent(MessageUtil.getMainMenu());
}else if("1".equals(reqContent))
{
// 获取网页源代码
//String html = httpRequest("http://ip.taobao.com/service/getIpInfo.php?ip=127.0.0.1");
textMessage.setContent("你要查看的是时政新闻");
}else
{
textMessage.setContent(MessageUtil.getMainMenu());
}
}else
{
textMessage.setContent(MessageUtil.getMainMenu());
}
return MessageUtil.textMessageToXml(textMessage);
}
}
下面一步我们来封装我们的工厂类,当然工厂类代码还是存在大量的if语句,这是一种不好的做法,如何消除这种代码,我们可以利用Java中的注解,反射机制来消除,本文就不介绍了。
/*
* @(#)MessageHandlerFactory.java 2014-3-16
*/
package com.lotus.weixin.reqhandler;
import com.lotus.weixin.message.utils.MessageUtil;
import com.lotus.weixin.reqhandler.impl.LocationMsgHandlerImpl;
import com.lotus.weixin.reqhandler.impl.PicMsgHandlerImpl;
import com.lotus.weixin.reqhandler.impl.TextMsgHandlerImpl;
import com.lotus.weixin.reqhandler.impl.VoiceMsgHandlerImpl;
/**
* 描述当前类的作用
*
* @author tsface
* @version 2014-3-16
* @since 1.0
* @see
*/
public class MessageHandlerFactory
{
/**
* 构造方法私有化
*/
private MessageHandlerFactory()
{
}
/**
* 生成实例的的方法
* @param msgType
* @return
*/
public static MessageHandler createMsgHandler(String msgType)
{
MessageHandler handler = null;
// 文本消息
if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT))
{
handler = new TextMsgHandlerImpl();
}
// 图片消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE))
{
handler = new PicMsgHandlerImpl();
}
// 地理位置消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION))
{
handler = new LocationMsgHandlerImpl();
}
// 链接消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK))
{
}
// 音频消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE))
{
handler = new VoiceMsgHandlerImpl();
}
return handler;
}
}
以上代码完成了我们对简单工厂的封装,下面我们看看客户端代码怎么写。有了工厂以后,我们只需用工厂产生我们需要的对象,调用接口提供的方法完成客户代码的解耦工作。
//获取消息处理接口
MessageHandler createMsgHandler = MessageHandlerFactory.createMsgHandler(msgType);
String xmlStr = createMsgHandler.buildXMlStr(requestMap);
f(StringUtils.isNotEmpty(xmlStr))
{
return xmlStr;
}else{
respContent = "/:p-(您发送的消息!暂时处理不了哎!";
}
以后即使新增了消息类型,那么客户端的代码我们就无需进行改动,只需要修改工厂类就可以实现,如果我们消除工厂类中的判断,改用读取配置文件或者注解来创建对象,那么我们代码就完全符合“对修改关闭,对增加开放”的原则了。
开闭原则:1988年,勃兰特·梅耶(Bertrand Meyer)在他的著作《面向对象软件构造(Object Oriented Software Construction)》中提出了开闭原则,它的原文是这样:“Software entities should be open for extension,but closed for modification”。翻译过来就是:“软件实体应当对扩展开放,对修改关闭”
2014/3/16 tsface 南京
hanily@msn.com