很多项目中都有消息分发或者事件通知机制,尤其是模块化程度高的项目。例如在办公自动化系统中,有些子系统对于新建用户这一事件很感兴趣,权限模块希望为这个新用户设置默认的权限,报表模块希望重新生成当月的报表,诸如此类的代码都写到新建用户的业务逻辑后面,会加大耦合度,可维护性降低,并且对于每个模块都是一个独立工程的情况,这种方式更是不可取。对于简单的情形,观察者模式就适用了,如果系统中有很多地方都需要收发消息,那么它就不适用了,否则会造成类数量的膨胀,增加类的复杂性,这时候就需要一种更集中的机制,Publish-Subscribe机制是个不错的选择,它的耦合性低,各个参与者之间毫无关联。每 一个消息都有一个唯一标识,一般都用字符串来描述,比如用户管理模块中新添加了一个用户,于是它发送了一个消息:/UserManagment/User /Add,消息的其他信息可以放置到一个Map中。下面是一个最简单的消息订阅接口:
public interface MessageSubscriber {
public void onRecived(String message,Map params);
}
当订阅的消息发出后,MessageSubscriber的onRecived方法就会被调用,消息相关的特定信息存储在参数params中。 一个消息可以被多个对象订阅,一个对象可以订阅多个消息,所以onRecived的第一个参数是消息的名称,如果对象订阅了多个消息,可能需要根据消息类型来进行具体的操作。
下面消息发送的实现类:
public class MessagePublisher {
private static MessagePublisher singleton;
private static Map<String,ArrayList<MessageSubscriber>> subscribers;
private MessagePublisher(){}
public static MessagePublisher instance(){
if(singleton == null)
singleton = new MessagePublisher();
return singleton;
}
public void register(String message,MessageSubscriber subscriber){
if(subscriber == null)
return;
if(subscribers == null)
subscribers = new LinkedHashMap<String, ArrayList<MessageSubscriber>>();
ArrayList<MessageSubscriber> subscriberList = subscribers.get(message);
if(subscriberList == null){
subscriberList = new ArrayList<MessageSubscriber>();
subscribers.put(message, subscriberList);
}
subscriberList.add(subscriber);
}
public void publish(String message, Map params){
if(subscribers == null)
return;
ArrayList<MessageSubscriber> subscriberList = subscribers.get(message);
if(subscriberList == null || subscriberList.isEmpty())
return;
for (MessageSubscriber topicSubscriber : subscriberList)
topicSubscriber.onRecived(message,params);
}
}
该类中主要包含两个方法:register用来注册消息订阅者,publish用来发送消息。这样,对某个事件感兴趣的模块就可以通过MessagePublisher来订阅这个相关的消息,而产生事件的模块就可以通过MessagePublisher将其发布出去,例如在新建用户逻辑的后面就可以加上以下代码片段
Map params = new LinkedHashMap();
params.put("id",newUserId);
params.put("name",newUserName);
MessagePublisher.instance().publish("/UserManagment/User/Add",params);
本文中的实例的唯一过滤依据就是消息的名称,在实际的项目中,过滤的方式可能更复杂,订阅者会提供其他过滤条件,只有这些条件被满足时,消息才会被发送给订阅者。另外,当消息发送出去后,订阅对象的onRecived方法会依次被调用,所以,订阅对象不应该在该方法中执行耗时操作,最好另外启动一个新线程来处理消息,不然会阻塞其他订阅对象收到该消息。
消息订阅机制的优点是大大降低了模块间的耦合度,相关操作都集中在MessagePublisher中;另外一个优点就是可扩展性强,随着系统越来越复杂,可以考虑把消息订阅和分发机制单独作为一个模块来实现,增加新特性以满足需求。消息订阅机制的缺点是发送者不能获知订阅者的执行情况。