1 基于Java API实现通知机制本文节选自《设计模式就该这样学》
当小伙伴们在社区提问时,如果有设置指定用户回答,则对应的用户就会收到邮件通知,这就是观察者模式的一种应用场景。有些小伙伴可能会想到MQ、异步队列等,其实JDK本身就提供这样的API。我们用代码来还原这样一个应用场景,首先创建GPer类。
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依赖包。
com.google.guava guava20.0
然后创建侦听事件GuavaEvent。
public class GuavaEvent { @Subscribe public void subscribe(String str){ //业务逻辑 System.out.println("执行subscribe方法,传入的参数是:" + str); } }
最后编写客户端测试代码。
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接口。
public interface EventListener { }
创建Event类。
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类。
public abstract class EventContext { protected Mapevents = new HashMap (); 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接口。
public interface MouseEventType { //单击 String ON_CLICK = "click"; //双击 String ON_DOUBLE_CLICK = "doubleClick"; //d起 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类。
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("调用d起方法"); 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类。
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("===========触发鼠标d起事件==========" + "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(); }
关注微信公众号『 Tomd架构 』回复“设计模式”可获取完整源码。
【推荐】Tomd架构:30个设计模式真实案例(附源码),挑战年薪60W不是梦
本文为“Tomd架构”原创,转载请注明出处。技术在于分享,我分享我快乐!
如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。关注微信公众号『 Tomd架构 』可获取更多技术干货!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)