您的位置:首页 > 编程语言 > Go语言

GoF著作中未提到的设计模式(7):Publish-Subscribe

2012-04-18 09:31 405 查看
很多项目中都有消息分发或者事件通知机制,尤其是模块化程度高的项目。例如在办公自动化系统中,有些子系统对于新建用户这一事件很感兴趣,权限模块希望为这个新用户设置默认的权限,报表模块希望重新生成当月的报表,诸如此类的代码都写到新建用户的业务逻辑后面,会加大耦合度,可维护性降低,并且对于每个模块都是一个独立工程的情况,这种方式更是不可取。对于简单的情形,观察者模式就适用了,如果系统中有很多地方都需要收发消息,那么它就不适用了,否则会造成类数量的膨胀,增加类的复杂性,这时候就需要一种更集中的机制,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中;另外一个优点就是可扩展性强,随着系统越来越复杂,可以考虑把消息订阅和分发机制单独作为一个模块来实现,增加新特性以满足需求。消息订阅机制的缺点是发送者不能获知订阅者的执行情况。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: