文章目录
案例展示——Observer怎么用?
观察者模式是一种非常通用的模式,以至于JDK都整合了这个设计模式,将其开放成编程接口供程序员使用:java.util.Observable和java.util.Observer。程序员只要实现这两个接口就能轻松使用观察者模式。现在我们先来说说原生的观察者模式是什么样的、怎么去使用这个设计模式。
假设有这样一种场景:想要升职,除了工作兢兢业业之外,还需要学会察言观色,从领导的一言一行中体会深意。领导有什么行动,自己也要做出相应改变,这叫顺势而为。如何通过编程来表达呢,看下面的类图:
类图元素分析:
-
ILeader接口:通用的领导接口,定义一组通用的方法,这些方法就是引发观察者进行观察的发生器。例如:下达命令(order)、回家(goHome)
-
Leader类:实现了ILeader接口和Observable接口
-
Observable接口:被观察者的通用接口,定义了一组方法:添加观察者、删除观察者和通知所有的观察者。所有实现了该接口的类都会被观察者观察
-
Observer接口:观察者接口,定义了一个方法:update(),该方法会应被观察者的行为变化而做出相应动作。所有实现了该接口的类都是观察者
下面是具体的代码实现:
// 被观察者接口
public interface Observable {
// 增加一个观察者
public void addObserver(Observer observer);
// 删除一个观察者
public void deleteObserver(Observer observer);
// 发生改变,通知观察者
public void notifyObservers(String context);
}
// 观察者接口
public interface Observer {
// 发现被观察者有变化,需要采取行动
public void update(String context);
}
// 领导接口
public interface ILeader {
// 领导下命令
public void order();
// 领导回家
public void goHome();
}
// 领导类
public class Leader implements ILeader, Observable {
// 定义一个变长数组,用于存放所有的观察者
private ArrayList<Observer> list = new ArrayList<Observer>(16);
// 领导下命令
public void order() {
System.out.println("领导下命令了!");
// 通知所有观察者
this.notifyObservers("领导下命令了!");
}
// 领导回家
public void goHome() {
System.out.println("领导要回家了!");
// 通知所有观察者
this.notifyObservers("领导要回家了!");
}
// 增加一个观察者
public void addObserver(Observer observer) {
this.list.add(observer);
}
// 删除一个观察者
public void deleteObserver(Observer observer) {
this.list.remove(observer);
}
// 通知所有的观察者
public void notifyObservers(String context) {
for (Observer observer : list) {
observer.update(context);
}
}
}
// 三个观察者
// 秘书
public class Secretary implements Observer {
// 观察领导要干什么
public void update(String context) {
System.out.println("领导要回家了,秘书和领导一起回家。。。");
}
}
// 司机
public class Driver implements Observer {
// 观察领导要干什么
public void update(String context) {
System.out.println("领导要回家了,司机将车从车库开出来!");
}
}
// 清洁工
public class Cleaner implements Observer {
// 观察领导要干什么
public void update(String context) {
System.out.println("领导要回家了,清洁工准备打扫办公室!");
}
}
// 在一个场景中运行代码
public class Client {
public static void main(String[] args) {
// 定义三个观察者
Observer secretary = new Secretary();
Observer driver = new Driver();
Observer cleaner = new Cleaner();
// 定义出被观察者:领导
Leader leader = new Leader();
// 三个观察者开始观察老板
leader.addObserver(secretary);
leader.addObserver(driver);
leader.addObserver(cleaner);
// 领导要回家,观察者开始行动
leader.goHome();
}
}
// 结果如下:
领导要回家了!
领导要回家了,秘书和领导一起回家。。。
领导要回家了,司机将车从车库开出来!
领导要回家了,清洁工准备打扫办公室!
深入分析——Observer是什么?
Observer的定义
观察者模式也叫发布订阅模式,这是一个经常会被用到的设计模式
定义: 定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。下面是通用类图:
类图分析如下:
-
Subject被观察者:定义被观察者必须实现的职责,它必须能够动态的增加、取消观察者。一般是一个抽象类或者实现类,仅完成作为被观察者必须实现的职责:管理观察者并通知观察者
-
Observer观察者:观察Subject的行为,接收到消息后触发相应操作(update())
-
ConcreteSubject具体的被观察者:定义被观察者自己的业务逻辑,同时定义对那些对象进行通知
-
ConcreteObserver具体观察者:接收消息,做出响应,每个观察者有自己的响应逻辑
其通用代码如下:
// 被观察者
public abstract class Subject {
// 定义一个观察者数组,所有的观察者都会被放到这个数组里
private List<Observer> list = new ArrayList<>(16);
// 增加一个观察者
public void addObserver(Observer o) {
this.list.add(o);
}
// 删除一个观察者
public void deleteObserver(Observer o) {
this.list.remove(o);
}
// 通知所有观察者
public void notifyObservers(Observer o) {
for(Observer o : list) {
o.uodate
}
}
}
// 具体的被观察者
public class ConcreteSubject extends Subject {
// 业务逻辑
public void doSomething() {
/**
* 业务
*/
// 通知观察者
super.notifyObservers();
}
}
// 观察者
public interface Observer {
// 更新方法
public void update();
}
//具体观察者
public class ConcreteObserver implements Observer {
// 实现更新方法
public void update() {
// 处理
}
}
// 场景类
public class Client {
public static void main(String[] args) {
// 创建一个被观察作者
ConcreteSubject subject = new ConcreteSubject();
// 定义一个观察者
Observer o = new ConcreteObserver();
// 观察者观察被观察者
subject.addObserver(o);
// 被观察者行动
subject.doSomething();
}
}
Observer的扩展
前面已经说过,观察者模式已经被整合到了JDK中,开发者只有实现java.util.Observable和java.util.Observer接口就能使用这个设计模式,下面是设计类图:
观察类图发现,与原来的设计相比,在被观察者java.util.Observable中,只有一个通知的方法,其他的方法都被剔除了,变得更加精简,下面来看看改动后的效果:
// 只给出改动部分代码,其他部分与上面相同
// 优化后的被观察者
public class Leader extends Observable implements ILeader {
// 领导下命令
public void order() {
System.out.println("领导下命令了!");
super.setChanged();
// 通知所有观察者
this.notifyObservers("领导下命令了!");
}
// 领导回家
public void goHome() {
System.out.println("领导要回家了!");
super.setChanged();
// 通知所有观察者
this.notifyObservers("领导要回家了!");
}
}
// 优化后的观察者
public class Secretary implements Observer {
// 观察领导要干什么
public void update(Observable o, Object obj) {
System.out.println("领导要回家了,秘书和领导一起回家。。。");
}
}
// 场景类
public class Client {
public static void main(String[] args) {
// 被观察者
Leader leader = new Leader();
// 观察者
Observer secretary = new Secretary();
// 观察者开始观察
leader.addObserver(secretary);
leader.goHome();
}
}
// 结果如下:
领导要回家了!
领导要回家了,秘书和领导一起回家。。。
Observer的优点
-
观察者和被观察者之间是抽象耦合:增加观察和被观察变得容易
-
建立了一套触发机制:被观察者一个对象的改变会引起多个对象作出回应
Observer的缺点
- 开发效率和运行效率问题:牵一发动全身,一个被观察者,多个观察者,开发调试会很困难
Observer的应用场景
-
关联行为场景
-
事件多级触发场景
-
跨系统的消息交换场景
在项目中使用Observer
-
观察者被观察者之间的消息沟通:在实际项目中,观察者的Update()方法接受两个参数,一个是被观察者,一个是DTO(数据传输对象:纯洁的JavaBean,由被观察者生成,由观察者消费)
-
观察者响应方式:假如有一个观察者多个被观察者那如何考虑性能
-
采用多线程技术,这就是异步架构
-
采用缓存技术,这就是同步架构
-
参考
《设计模式之禅》