假设我们要关心一些事物发生的状态 那么我们可能就需要不断的对这个事物的状态进行查询 而这显然是很低效的 最好的方式应该是当这个事物发生变化时 它会通知我们 而不是我们一味的去查询 这显然会节省大量的时间 这种通知方式就是观察者的设计模式,当某个对象发生状态改变需要通知第三方的时候,观察者模式就特别适合胜任这样的工作 下面我们先看一个比较简单的例子
假设有一个订阅号 每当它发布新文章的时候 它就会通知所有订阅过的用户 用户当收到文章若不喜欢 它可以退订 此后就收不到这个订阅号更新的信息了,这个事件观察者设计模式是很好胜任的,订阅号就相当于是事件源,它有新的推送就相当于状态发生变化,然后就会通知有订阅的观察者,即用户。要实现这个例子,首先显然需要设计一个Observer的集合 它就是承载用户的集合 它就是观察者 当这个订阅号发布文章的时候 就会向这些观察者更新信息
首先先定义一个Observer的接口 里面只有一个方法就是更新 给观察者实现 即给用户实现
public interface Observer { void update(); }
然后定义一个ObserversWay的接口 它是订阅号实现的 订阅号显然是清楚整个事物的状态发生的变化 可以向各个观察者发送更新的信息,用户退订和订阅即为移除观察者和添加观察者
public interface ObserversWay { void add(Observer observer); //添加观察者 void remove(Observer observer);//移除观察者,即移除用户 void notifyAllObservers();//更新信息 }
接下来是订阅号的具体实现
public class Subject implements ObserversWay{
List<Observer> Observers; //定义一个观察者的队列 承载用户
public Subject() {
Observers = new ArrayList<>();
}
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
if (this.msg == msg) {
return;
}
this.msg = msg;
notifyAllObservers(); //当发表新文章时更新信息
}
@Override
public void add(Observer observer) { //添加用户
this.Observers.add(observer);
}
@Override
public void remove(Observer observer) { //用户退订
this.Observers.remove(observer);
}
@Override
public void notifyAllObservers() {
for (Observer observer : Observers) { //向所有用户发送更新的信息
observer.update();
}
}
}
接下来是用户的实现
public class User implements Observer { private final String name; public User(String name) { this.name = name; } @Override public void update(String message) { System.out.println(this.name + ":has received " + message); //发表新消息时触发的方法 } }
接下来是测试
public static void main(String[] args) { Subject subject = new Subject(); User user1 = new User("lakersFans A"); User user2 = new User("CelticFans"); User user3 = new User("lakersFans B"); //用户1、2、3订阅了该订阅号
subject.add(user1); subject.add(user2); subject.add(user3); subject.setMsg("湖人总冠军"); //凯尔特人球迷看到这条推送后果断退订
subject.remove(user2); System.out.println("======================="); subject.setMsg("凯尔特人总冠军"); //这条推送凯尔特人粉丝就看不见了
}
结果:
lakersFans A:has received 湖人总冠军 CelticFans:has received 湖人总冠军 lakersFans B:has received 湖人总冠军 ======================= lakersFans A:has received 凯尔特人总冠军 lakersFans B:has received 凯尔特人总冠军
在对观察者模式有了初步的了解后,接下来我们来对更具体的场景进行分析 通过观察者模式去实现如何对一个任务的生命周期进行观察 首先需要定义一个枚举类型
定义任务的生命周期状态
public enum Cycle { STARTED,RUNNING,DONE,ERROR }
在定义好枚举类型后 定义一个关于任务生命周期的接口 当这个任务发生状态变化hi通知监控者时,监控者对应的执行方法 相当于上述例子中更新推送时会执行的update方法
public interface TaskLifeCycle<T> {
//这个任务开始时触发的方法 void onStart(Thread thread); //这个任务运行时触发的方法 void onRunning(Thread thread); //这个任务完成时触发的方法 result为关心的返回值 void onFinish(Thread thread,T result); //出现异常时触发的方法 void onError(Thread thread, Exception e); }
接下来定义一个调用者的接口 通过这个接口的实现 来实现整个监控流程的实现 被观察的任务会实现这个接口 当它发生状态变化时 就会触发上述的方法
public interface Observable { //获取当前任务的生命周期
Cycle getCycle(); //启动线程去监控 还有一个作用是屏蔽Thread的其他API
void start(); //对当前监控线程进行打断
void interrupt(); }
最后定义一个返回值的接口
public interface Task<T> {
//主要是需要关心返回值时调用 T call(); }
接下来是调用者监控时的具体实现 通过这个方法 会对任务的生命周期进行监控 当任务的生命周期发生变化时 任务就会通知调用者 让调用者执行
public final class ObservableThread<T> extends Thread implements Observable { //定义的监控者实现 监控者根据状态变化采取的行动 private final TaskLifeCycle<T> lifeCycle; //返回值 private final Task<T> task; //状态 private Cycle cycle; public ObservableThread(TaskLifeCycle<T> lifeCycle, Task<T> task) { //Thread的构造方法
super(); if (task == null) throw new IllegalArgumentException("Task is not allowed for null"); this.lifeCycle = lifeCycle; this.task = task; } //更新状态 private void update(Cycle cycle, T result, Exception e) { this.cycle = cycle; if (lifeCycle == null) { return; } try { switch (cycle) { case STARTED: this.lifeCycle.onStart(currentThread()); break; case RUNNING: this.lifeCycle.onRunning(currentThread()); break; case DONE: this.lifeCycle.onFinish(currentThread(), result); break; case ERROR: this.lifeCycle.onError(currentThread(), e); break; } } catch (Exception ex) { if (cycle == Cycle.ERROR) { throw ex; } } } //被监控的任务的逻辑实现单元 它执行到哪一个阶段就会触发相应的方法,即监控者定义的方法 @Override public void run() { this.update(Cycle.STARTED, null, null); try {this.update(Cycle.RUNNING, null, null); TimeUnit.SECONDS.sleep(5); //睡眠5秒模拟工作 T result = this.task.call(); this.update(Cycle.DONE, result, null); } catch (Exception e) { this.update(Cycle.ERROR, null, e); //发生异常时触发的方法 } } //获取任务的执行状态 @Override public Cycle getCycle() { return this.cycle; } }
接下来简单实现监控者的接口,设立发生状态变化时需要执行的对应方法
public class lifeCycle<T> implements TaskLifeCycle<T> { @Override public void onStart(Thread thread) { System.out.println("i started"); } @Override public void onRunning(Thread thread) { System.out.println("i am working"); } @Override public void onFinish(Thread thread, T result) { System.out.println("i finished"); System.out.println(result); } @Override public void onError(Thread thread, Exception e) { System.out.println("i went wrong"); } }
接下来是测试
public static void main(String[] args) { lifeCycle lifeCycle = new lifeCycle(); ObservableThread observableThread = new ObservableThread(lifeCycle, () -> "任务完成啦"); observableThread.start(); }
结果
i started
i am working
i finished
任务完成啦 //定义的返回值
如果在observableThread的run方法中添加一个1/0,结果如下
i started
i am working
i went wrong
总结:在这个监控任务生命周期的实现中 充当事件源的是ObservableThread,它的run方法就是任务的逻辑单元和事件的发起者,在执行过程中若发生状态变化就会触发监控者定义好的方法,即TaskLifeCycle中定义的方法,它相当于事件回调的响应者