乐趣区

关于java:基于Guava-API实现异步通知和事件回调

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

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 弹架构』可获取更多技术干货!

退出移动版