消息发送组件
设计一个发送消息的组件,可以发送普通消息、加急消息和特急消息,不同的消息类型处理逻辑不同,加急消息需要在消息上添加“加急”字样,特急消息除了添车“特急”字样外还会定时催促,至到完成(需要记录该消息是否已被完成的状态)。消息发送可以支持多种方式如:站内信、邮件、手机短信等。
思考过程
作为消息发送组件,我们希望它能提供友好的API调用,并且对调用者屏蔽具体的实现,实际上调用者也不关心其具体实现。
1、希望组件提供的API:
消息组件.发送(消息,级别,发送方式)
MessageComponent.sendMessage(Message msg,MessageLevel.level1, SendType.All);
MessageLeve作为静态常量类定义了各种消息级别:普通消息,加急消息,特急消息等;SendType作为静态常量类定义了消息发送的方式:站内信、邮件、短信等;
这样设计API的好处是调用简单,无需关心具体实现,方便以后扩展:扩展消息类型和发送方式对调用端都不会产生影响。
2、OO设计原则之一是:对修改关闭对扩展开放,消息组件中可能扩展的地方:消息的类型:如增加严重级别的消息,如果该消息通知的内容不被处理,用户不能进行任何其它操作;发送方式:通过WebService通知“核心系统”某消息。任何一种类型的消息可以通过任何一种方式发送-->说明消息与发送方式可以任意组合。以上两点完全符合桥接模式:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
类图:
Message中一个消息发送器的集合,消息与消息发送器是一对多的关系:一条消息可以被多种消息发送器发送。
示意代码:
/** * 所有消息的抽象父类 * @author yuhq * */ public abstract class Message { //消息发送器集合 private List<MessageSender> senderList; //消息内容对象 private MsgVO msgVO; public void setMessage(MsgVO msgVO){ this.msgVO = msgVO; } /** * 设置消息发送器集合 * @param senderList 消息发送器集合 */ public void setMsgSenderList(List<MessageSender> senderList){ this.senderList = senderList; } /** * 发布消息 */ public void sendMessage(){ //遍历消息发送器,发送消息 for (MessageSender sender : senderList) { //过滤消息发送器 if(filterMsgSender(sender)) continue; //发送消息 if(!sender.send(msgVO)){ //如果消息发送失败,将消息记录到文件或是数据库中,通过定时任务来处 //理发送失败的消息,为了不影响正常业务处理 } } } /** * 子类扩展该方法可以实现根据指定条件过滤某些消息发送器,默认不过滤任务消息发送器 * @param sender 消息发送器 * @return true:表示过虑,false:不过滤 */ public boolean filterMsgSender(MessageSender sender){ return false; } } /** * 消息内容对象 * @author yuhq * */ public class MsgVO { //消息内容 private String msg; //消息状态 private String satatus; //消息发布者 private String promulgator; //消息创建时间:yyyy-MM-dd hh:mm:ss private String dateTime; //其它属性 //setter and getter方法 } /** * 紧急消息,对消息进行处理 * @author yuhq * */ public class UrgentMessage extends Message{ @Override public void setMessage(MsgVO msgVO) { //添加消息处理 handleMessage(msgVO); super.setMessage(msgVO); } /** * 对消息进行处理 * @param msgVO 消息内容对象 */ public void handleMessage(MsgVO msgVO){ msgVO.setMsg("特急:"+msgVO.getMsg()); } } /** * 特急消息处理,在消息中添加特急字样,并对未处理的消息一直提醒 * @author yuhq * */ public class ExtraUrgentMessage extends Message{ //启动定时调度任务,查询消息状态,一直提醒未处理的消息 static{ //TODO } @Override public void setMessage(MsgVO msgVO) { //添加消息处理 handleMessage(msgVO); super.setMessage(msgVO); } /** * 对消息进行处理 * @param msgVO 消息内容对象 */ public void handleMessage(MsgVO msgVO){ msgVO.setMsg("特急:"+msgVO.getMsg()); } /** * 记录消息,并将消息状态修改为“未处理” */ public void watch(){ //TODO } } /** * 消息发送器的抽象对象 * @author yuhq * */ public abstract class MessageSender { /** * 发送消息,由子类具体实现站内信、邮件、短信等方式 * @param msgVO 消息内容对象 * @return */ public abstract boolean send(MsgVO msgVO); } /** * 邮件发送器 * @author yuhq * */ public class EmailMessageSender extends MessageSender{ /** * 发送消息,从配置文件中读取邮箱配置配置信并发送邮件 */ public boolean send(MsgVO msgVO) { //具体发送代码 return true; } }3、有了消息及消息发送器,再提供桥接模式中的Client,即是这里消息组件对外提供的调用API
/** * 消息发送组件 * @author yuhq * */ public class MessageComponent { /** * 消息发送 * @param msgVO 消息内容对象 * @param msgLevel 消级级别 * @param sendTypes 发送方式 */ public void sendMessage(MsgVO msgVO,int msgLevel, int[] sendTypes){ Message message = null;//消息 List<MessageSender> senderList = new ArrayList<MessageSender>();//消息发送器 switch (msgLevel) { //紧急消息 case MsgLevel.URGENT_MSG: message = new UrgentMessage(); break; //特急消息 case MsgLevel.NORMAL_MSG: message = new ExtraUrgentMessage(); break; //普通消息 default: message = new NormalMessage(); break; } for (int i = 0; i < sendTypes.length; i++) { switch (sendTypes[i]) { //邮件发送 case SendType.EMAIL_SEND: senderList.add(new EmailMessageSender()); break; //短信发送 case SendType.NOTE_SEND: senderList.add(new NoteMessageSender()); break; //站内信发送 default: senderList.add(new InteriorMessageSender()); break; } } //设置消息发送器 message.setMsgSenderList(senderList); //发送消息 message.sendMessage(); } /** * 消息级别 * @author yuhq * */ class MsgLevel{ /** * 普通消息 */ public static final int NORMAL_MSG = 0; /** * 紧急消息 */ public static final int URGENT_MSG = 1; /** * 特急消息 */ public static final int EXTRA_URGENT_MSG = 2; } /** * 消息发送方式静态常量类 * @author yuhq * */ class SendType{ /** * 站内信发送 */ public static final int INTERIOR_SEND = 0; /** * 邮件发送 */ public static final int EMAIL_SEND = 1; /** * 短信发送 */ public static final int NOTE_SEND = 2; /** * 所有方式发送 */ public static final int ALL_SEND = 3; } }4、到这里已经将消息组件的主要设计思路理清楚了,还有一些与桥接模式无关的细化工作需要完成,待续...