首页 > 设计模式 > 设计模式之侦听者模式

设计模式之侦听者模式

2014年11月23日 发表评论 阅读评论

关于技术,老夫一直认为应该以实用为主,至于那些理论性的东西,用得多了慢慢就理解了,所以为了说明今天这个设计模式,我们先提出一个问题:我们知道很多系统都有注册功能,有些呢,直接返回您已注册成功请直接登录,而有些注册则要求相对比较比较高,例如注册成功之后需要向用户填写的手机发送短信、Email发送邮件之类的,关于这个问题,大家立马想到的也许是这么来实现吧:

package cn.bridgeli.regdemo.service;

public class UserService {

    public void register(String username, String password) {
        // 非空验证

        // save到数据库

        // 发送短信说,注册成功

        // 发送邮件说,注册成功
    }
}

这是一个很中规中矩的写法,我们都知道面向对象有一个原则是:单一职责原则,也即是最小知识化原则,好像也称迪米特原则和不和陌生人说话,不管怎么说,就是一个类只管一个类型的东西,一个方法只干一件事,例如本例中的注册,那么应该只干注册一件事,至于什么发短信啊,发邮件啊,本质上来说和注册是没有关系的,所以我们可以把发短信,发邮件的方法提取出来,放到其他的地方,例如放到工具类里面,那么提取出来是不是就是最好的了呢?我们应该知道面向对象还有一个原则:开闭原则,这个原则是说,对扩展开放对修改关闭,也就是说,当我们需求发生变化的时候,不应该依赖于去修改源码,而是依赖于对源码的扩展,所以关于我们这个例子:假设有一天我们不需要发送短信了,或者需要有第三种通知用户的方式,您是否能做到不修改源码呢?肯定做不到吧,只有把调用发送短信的代码删了,或者在下面添加第三种通知方式,所以这么做肯定还是不够的,那么为了满足:开闭原则,我们就要引入今天的设计模式:侦听者模式,且看下面的例子:

package cn.bridgeli.regdemo.service;

import cn.bridgeli.regdemo.listener.EventLinstener;

public class UserService {

    public void register(String username, String password) {
        // 非空验证

        // save到数据库

        EventLinstener eventLinstener = new EventLinstener();
        String data = "注册成功";
        eventLinstener.dispatchEvent("REGSUCESSED", data);
    }
}

核心类EventLinstener

package cn.bridgeli.regdemo.listener;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class EventLinstener {

    public static Map<String, List<Observer>> events = new HashMap<String, List<Observer>>();

    static {
        List<Observer> reg = new ArrayList<Observer>();
        reg.add(new EmailObserver());
        reg.add(new SmsObserver());
        events.put("REGSUCESSED", reg);
    }

    public void dispatchEvent(String eventName, Object object) {
        List<Observer> observers = events.get(eventName);
        if (null != object && !observers.isEmpty()) {
            for (Observer observer : observers) {
                observer.execute(object);
            }
        }
    }
}

侦听者抽象类Observer

package cn.bridgeli.regdemo.listener;

public interface Observer {
    void execute(Object object);
}

两个侦听者实现类
EmailObserver

package cn.bridgeli.regdemo.listener;

public class EmailObserver implements Observer {
    @Override
    public void execute(Object object) {
        System.out.println("发送邮件。。。");
    }
}

SmsObServer

package cn.bridgeli.regdemo.listener;

public class SmsObserver implements Observer {
    @Override
    public void execute(Object object) {
        System.out.println("发送短信。。。");
    }
}

这样的话,我们就实现了侦听者模式,注册的方法只管注册,侦听者核心类知道有哪些类在监听,他有一个方法负责分发这一事件,调用具体的方法去实现自己的逻辑,那么这么一来,可能会有人问:你这么一弄就能实现开闭原则吗?就像刚才一样,如果我们不发邮件了,是不是还是需要更改EventLinstener类中static代码块,这么写是肯定的,但如果我们和工厂模式结合的,这一段不是由我们在代码里面写死,而是从一个XML文件中读取的话,是不是就不用更改这一段了,如果有不需要发邮件了,那么我们只需要删除XML里面的一个配置,如果我们需要其他的通知方法同样需要在读取的那个XML文件中增加一个配置,当然也要增加相应的侦听者类,只需要实现Observer接口就行了,那么这么一做,我们是不是就满足了开闭原则。

注:有些人可能会说,更改了XML文件也是改了啊,所以我们还是有一个约定:XML不算源文件

分享到:
作 者: BridgeLi,http://www.bridgeli.cn/
原文链接:https://www.bridgeli.cn/archives/116
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。
  1. Java小神
    2014年11月27日20:28 | #1

    这个评论插件有的坑啊,输名字就算了,还要邮箱。。。。。
    你用个list岂不是短信邮箱都发了。。。。

  2. Java小神
    2014年11月27日20:29 | #2

    我写评论居然没了,这评论插件。。。。

    • Bridge Li
      2014年11月28日09:33 | #3

      关于输名字和邮箱,这是wp本身要求的,懒得改了,但老夫保证:作为一个有节操的博主,老夫是不会给您们发垃圾邮件的,这个敬请放心,还请您多留言交流; 至于评论没了,是wp把您的评论当然垃圾评论给过滤了,老夫已帮您还原了,由此给您带来的不便,敬请谅解,谢谢

  1. 本文目前尚无任何 trackbacks 和 pingbacks.