前言:继续《设计模式就该这么学》系列文章,今天以当前比较火的微信订阅号给大家介绍应用得比较多的一种设计模式——观察者模式,之后再来介绍java拉模型方式的内置设计模式实现,最后附带一个项目实际观察者应用的例子!
《设计模式就该这么学》系列文章:
设计模式就该这么学:为什么要学设计模式?(开篇漫谈)
设计模式就该这么学:要走心才能遵循设计模式五大原则(第二篇)
设计模式就该这么学:以微信订阅号来讲观察者模式(第三篇)
观察者模式实际应用:监听线程,意外退出线程后自动重启
在观察者模式中,又分为推模型和拉模型两种方式。
而它们的区别在于:
“推”的好处包括:
1、高效。如果没有更新发生,不会有任何更新消息推送的动作,即每次消息推送都发生在确确实实的更新事件之后,所以这种推送是有意义的。
2、实时。事件发生后的第一时间即可触发通知操作。
“拉”的好处包括:
1、如果观察者众多,那么主题要维护订阅者的列表臃肿,把订阅关系解脱到Observer去完成,什么时候要自己去拉数据就好了。
2、Observer可以不理会它不关心的变更事件,只需要去获取自己感兴趣的事件即可。
根据上面的描述,发现前面的例子就是典型的推模型,下面我先来介绍下java内置的拉模型设计模式实现,再给出一个拉模型的实例。
在JAVA编程语言的java.util类库里面,提供了一个Observable类以及一个Observer接口,用来实现JAVA语言对观察者模式的支持。
Observer接口:这个接口代表了观察者对象,它只定义了一个方法,即update()方法,每个观察者都要实现这个接口。当主题对象的状态发生变化时,主题对象的notifyObservers()方法就会调用这一方法。
public interface Observer { void update(Observable o, Object arg); }
Observable类:这个类代表了主体对象,主题对象可以有多个观察者,主题对象发生变化时,会调用Observable的notifyObservers()方法,此方法调用所有的具体观察者的update()方法,从而使所有的观察者都被通知更新自己
package java.util; public class Observable { private boolean changed = false; private Vector obs; public Observable() { obs = new Vector<>(); } //添加一个观察者 public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } //删除一个观察者 public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } public void notifyObservers() { notifyObservers(null); } //通知所有的观察者 public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } //调用Observer类通知所有的观察者 for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } public synchronized void deleteObservers() { obs.removeAllElements(); } protected synchronized void setChanged() { changed = true; } protected synchronized void clearChanged() { changed = false; } //省略...... }
接下来再介绍我用java这种内置的观察者设计模式在项目中的一个实际应用,详细请看我的这篇博文:观察者模式实际应用:监听线程,意外退出线程后自动重启
这里只介绍下思路:
项目场景:用户那边会不定期的上传文件到一个ftp目录,我需要实现新上传的文件做一个自动检测,每次只要有文件新增,自动解析新增文件内容入库,并且要保证该功能的稳定性。狘/p>
实现思路:
1、监听器初始化创建:首先在tomcat启动的时候,利用监听器初始化创建一个监控文件新增线程,如下:
@Component public class ThreadStartUpListenser implements ServletContextListener { //监控文件新增线程 private static WatchFilePathTask r = new WatchFilePathTask(); private Log log = LogFactory.getLog(ThreadStartUpListenser.class); @Override public void contextDestroyed(ServletContextEvent paramServletContextEvent) { // r.interrupt(); } @Override public void contextInitialized(ServletContextEvent paramServletContextEvent) { //将监控文件类添加为一个观察者,并启动一个线程 ObserverListener listen = new ObserverListener(); r.addObserver(listen); new Thread(r).start(); // r.start(); log.info("ImportUserFromFileTask is started!"); } }
2、主体对象:即下面的监控文件新增类WatchFilePathTask ,每次有新文件进来,自动解析该文件,挂掉之后,调用动doBusiness()里面的notifyObservers()方法,伪代码如下:
//继承java内置观察者模式实现的Observable 类 public class WatchFilePathTask extends Observable implements Runnable { private Log log = LogFactory.getLog(WatchFilePathTask.class); private static final String FILE_PATH = ConfigUtils.getInstance() .getValue("userfile_path"); private WatchService watchService; /** * 此方法一经调用,立马可以通知观察者,在本例中是监听线程 */ public void doBusiness() { if (true) { super.setChanged(); } notifyObservers(); } @Override public void run() { try { //这里省略监控新增文件的方法 }catch (Exception e) { e.printStackTrace(); doBusiness();// 在抛出异常时调用,通知观察者,让其重启线程 } } }
3、观察者对象:即上面出现的ObserverListener类,当主题对象的的notifyObservers()方法被调用的时候,就会调用该类的update()方法,伪代码如下:
//实现java内置观察者模式实现的Observer接口,并且注册主题WatchFilePathTask,以便线程挂掉的时候,再重启这个线程 public class ObserverListener implements Observer { private Log log = LogFactory.getLog(ObserverListener.class); /** * @param o * @param arg */ public void update(Observable o, Object arg) { log.info("WatchFilePathTask挂掉"); WatchFilePathTask run = new WatchFilePathTask(); run.addObserver(this); new Thread(run).start(); log.info("WatchFilePathTask重启"); } }
关于这个例子更多详细实现,请查看我的这篇文章:观察者模式实际应用:监听线程,意外退出线程后自动重启
?学习本就是一个不断模仿、练习、再到最后面自己原创的过程。
虽然可能从来不能写出超越网上通类型同主题博文,但为什么还是要写?
于自己而言,博文主要是自己总结。假设自己有观众,毕竟讲是最好的学(见下图)。于读者而言,笔者能在这个过程get到知识点,那就是双赢了。
当然由于笔者能力有限,或许文中存在描述不正确,欢迎指正、补充!
感谢您的阅读。如果本文对您有用,那么请点赞鼓励。
?
当前文章:http://www.carinsurancequoteny.com/nprhm/95304-664939-68363.html
发布时间:00:17:23
香港马会开奖现场直播 二万五论坛 高手论坛免费资料大全 www.941122.com 246免费资料大全天下 六合财神网 包租婆高手心水论坛 欢人阁下光临神码堂 大赢家心水论坛60990 188144现场报码