本文节选自《设计模式就该这样学》

1 基于Java API实现告诉机制

当小伙伴们在社区发问时,如果有设置指定用户答复,则对应的用户就会收到邮件告诉,这就是观察者模式的一种利用场景。有些小伙伴可能会想到MQ、异步队列等,其实JDK自身就提供这样的API。咱们用代码来还原这样一个利用场景,首先创立GPer类。

/** * JDK提供的一种观察者的实现形式,被观察者 */public class GPer extends Observable{    private String name = "GPer生态圈";    private static GPer gper = null;    private GPer(){}    public static GPer getInstance(){        if(null == gper){            gper = new GPer();        }        return gper;    }    public String getName() {        return name;    }    public void publishQuestion(Question question){        System.out.println(question.getUserName() + "在" + this.name + "上提交了一个问题。");        setChanged();        notifyObservers(question);    }}

而后创立问题Question类。

public class Question {    private String userName;    private String content;    public String getUserName() {        return userName;    }    public void setUserName(String userName) {        this.userName = userName;    }    public String getContent() {        return content;    }    public void setContent(String content) {        this.content = content;    }}

接着创立老师Teacher类。

public class Teacher implements Observer {    private String name;    public Teacher(String name) {        this.name = name;    }    public void update(Observable o, Object arg) {        GPer gper = (GPer)o;        Question question = (Question)arg;        System.out.println("======================");        System.out.println(name + "老师,你好!\n" + "您收到了一个来自" + gper.getName() + "的发问,心愿您解答。问题内容如下:\n" +                   question.getContent() + "\n" + "提问者:" + question.getUserName());    }}

最初编写客户端测试代码。

    public static void main(String[] args) {        GPer gper = GPer.getInstance();        Teacher tom = new Teacher("Tom");        Teacher jerry = new Teacher("Jerry");        gper.addObserver(tom);        gper.addObserver(jerry);        //用户行为        Question question = new Question();        question.setUserName("张三");        question.setContent("观察者模式实用于哪些场景?");        gper.publishQuestion(question);}

运行后果如下图所示。

2 基于Guava API轻松落地观察者模式

笔者向大家举荐一个实现观察者模式的十分好用的框架,API应用也非常简单,举个例子,首先引入Maven依赖包。

<dependency>    <groupId>com.google.guava</groupId>    <artifactId>guava</artifactId>    <version>20.0</version></dependency>

而后创立侦听事件GuavaEvent。

/** * Created by Tom */public class GuavaEvent {    @Subscribe    public void subscribe(String str){        //业务逻辑        System.out.println("执行subscribe办法,传入的参数是:" + str);    }}

最初编写客户端测试代码。

/** * Created by Tom */public class GuavaEventTest {    public static void main(String[] args) {        EventBus eventbus = new EventBus();        GuavaEvent guavaEvent = new GuavaEvent();        eventbus.register(guavaEvent);        eventbus.post("Tom");    }}

3 应用观察者模式设计鼠标事件响应API

再来设计一个业务场景,帮忙小伙伴们更好地了解观察者模式。在JDK源码中,观察者模式的利用也十分多。例如java.awt.Event就是观察者模式的一种,只不过Java很少被用来写桌面程序。咱们用代码来实现一下,以帮忙小伙伴们更粗浅地理解观察者模式的实现原理。首先,创立EventListener接口。

/** * 观察者形象 * Created by Tom. */public interface EventListener {}

创立Event类。

/** * 规范事件源格局的定义 * Created by Tom. */public class Event {    //事件源,动作是由谁收回的    private Object source;    //事件触发,要告诉谁(观察者)    private EventListener target;    //观察者的回应    private Method callback;    //事件的名称    private String trigger;    //事件的触发事件    private long time;    public Event(EventListener target, Method callback) {        this.target = target;        this.callback = callback;    }    public Object getSource() {        return source;    }    public Event setSource(Object source) {        this.source = source;        return this;    }    public String getTrigger() {        return trigger;    }    public Event setTrigger(String trigger) {        this.trigger = trigger;        return this;    }    public long getTime() {        return time;    }    public Event setTime(long time) {        this.time = time;        return this;    }    public Method getCallback() {        return callback;    }    public EventListener getTarget() {        return target;    }    @Override    public String toString() {        return "Event{" +                "source=" + source +                ", target=" + target +                ", callback=" + callback +                ", trigger='" + trigger + '\'' +                ", time=" + time +                '}';    }}

创立EventContext类。

/** * 被观察者的形象 * Created by Tom. */public abstract class EventContext {    protected Map<String,Event> events = new HashMap<String,Event>();    public void addListener(String eventType, EventListener target, Method callback){        events.put(eventType,new Event(target,callback));    }    public void addListener(String eventType, EventListener target){        try {            this.addListener(eventType, target, target.getClass().getMethod("on"+toUpperFirstCase(eventType), Event.class));        }catch (NoSuchMethodException e){            return;        }    }    private String toUpperFirstCase(String eventType) {        char [] chars = eventType.toCharArray();        chars[0] -= 32;        return String.valueOf(chars);    }    private void trigger(Event event){        event.setSource(this);        event.setTime(System.currentTimeMillis());        try {            if (event.getCallback() != null) {                //用反射调用回调函数                event.getCallback().invoke(event.getTarget(), event);            }        }catch (Exception e){            e.printStackTrace();        }    }    protected void trigger(String trigger){        if(!this.events.containsKey(trigger)){return;}        trigger(this.events.get(trigger).setTrigger(trigger));    }}

而后创立MouseEventType接口。

/** * Created by Tom. */public interface MouseEventType {    //单击    String ON_CLICK = "click";    //双击    String ON_DOUBLE_CLICK = "doubleClick";    //弹起    String ON_UP = "up";    //按下    String ON_DOWN = "down";    //挪动    String ON_MOVE = "move";    //滚动    String ON_WHEEL = "wheel";    //悬停    String ON_OVER = "over";    //失去焦点    String ON_BLUR = "blur";    //取得焦点    String ON_FOCUS = "focus";}

创立Mouse类。

/** * 具体的被观察者 * Created by Tom. */public class Mouse extends EventContext {    public void click(){        System.out.println("调用单击办法");        this.trigger(MouseEventType.ON_CLICK);    }    public void doubleClick(){        System.out.println("调用双击办法");        this.trigger(MouseEventType.ON_DOUBLE_CLICK);    }    public void up(){        System.out.println("调用弹起办法");        this.trigger(MouseEventType.ON_UP);    }    public void down(){        System.out.println("调用按下办法");        this.trigger(MouseEventType.ON_DOWN);    }    public void move(){        System.out.println("调用挪动办法");        this.trigger(MouseEventType.ON_MOVE);    }    public void wheel(){        System.out.println("调用滚动办法");        this.trigger(MouseEventType.ON_WHEEL);    }    public void over(){        System.out.println("调用悬停办法");        this.trigger(MouseEventType.ON_OVER);    }    public void blur(){        System.out.println("调用取得焦点办法");        this.trigger(MouseEventType.ON_BLUR);    }    public void focus(){        System.out.println("调用失去焦点办法");        this.trigger(MouseEventType.ON_FOCUS);    }}

创立回调办法MouseEventLisenter类。

/** * 观察者 * Created by Tom. */public class MouseEventListener implements EventListener {    public void onClick(Event e){        System.out.println("===========触发鼠标单击事件==========" + "\n" + e);    }    public void onDoubleClick(Event e){        System.out.println("===========触发鼠标双击事件==========" + "\n" + e);    }    public void onUp(Event e){        System.out.println("===========触发鼠标弹起事件==========" + "\n" + e);    }    public void onDown(Event e){        System.out.println("===========触发鼠标按下事件==========" + "\n" + e);    }    public void onMove(Event e){        System.out.println("===========触发鼠标挪动事件==========" + "\n" + e);    }    public void onWheel(Event e){        System.out.println("===========触发鼠标滚动事件==========" + "\n" + e);    }    public void onOver(Event e){        System.out.println("===========触发鼠标悬停事件==========" + "\n" + e);    }    public void onBlur(Event e){        System.out.println("===========触发鼠标失去焦点事件==========" + "\n" + e);    }    public void onFocus(Event e){        System.out.println("===========触发鼠标取得焦点事件==========" + "\n" + e);    }}

最初编写客户端测试代码。

    public static void main(String[] args) {        EventListener listener = new MouseEventListener();        Mouse mouse = new Mouse();        mouse.addListener(MouseEventType.ON_CLICK,listener);        mouse.addListener(MouseEventType.ON_MOVE,listener);        mouse.click();        mouse.move();    }        

关注微信公众号『 Tom弹架构 』回复“设计模式”可获取残缺源码。

【举荐】Tom弹架构:30个设计模式实在案例(附源码),挑战年薪60W不是梦
本文为“Tom弹架构”原创,转载请注明出处。技术在于分享,我分享我高兴!
如果本文对您有帮忙,欢送关注和点赞;如果您有任何倡议也可留言评论或私信,您的反对是我保持创作的能源。关注微信公众号『 Tom弹架构 』可获取更多技术干货!