观察者模式,你觉得在你的项目中用得多不多?
哪些地方用到了观察者模式?
为什么要用观察者模式?
观察者模式(Observer Pattern),定义了对象之间一对多依赖,让多个观察者同时监听一个主体对象,当主体对象发生变化时,它的所有依赖者也就是观察者都会收到通知并被自动更新。它是一种行为型模式。
业务场景:动态通知,订阅发布等场景。
关键代码:通过一个聚合对象对观察者进行聚合。
下面看UML类图:
类图说明:抽象观察者AbstractObserver和HexObserver、BinaryObserver,它们之间是被继承、继承关系。抽象观察者AbstractObserver依赖了主体类Subject,同时主体类Subject又聚合了抽象观察者,每次发布事件时,只对加入队列的观察者进行通知。这个图中有三种关系:继承、依赖、聚合。
下面看代码实现步骤:
1.观察者抽象类;
/**
* 1.观察者抽象类
* @author 程就人生
* @Date
*/
public abstract class AbstractObserver {
// 主题对象的依赖
protected Subject subject;
// 观察者改变事件
public abstract void subscribe();
}
2.观察者实现类;
/**
* 2.1 观察者抽象接口的实现类
* @author 程就人生
* @Date
*/
public class BinaryObserver extends AbstractObserver {
public BinaryObserver(Subject subject) {
this.subject = subject;
// 加入到观察者队列
this.subject.addObserver(this);
}
@Override
public void subscribe() {
System.out.println("binary string :" + Integer.toBinaryString(this.subject.getPublish()));
}
}
/**
* 2.2 观察者抽象接口的实现类
* @author 程就人生
* @Date
*/
public class HexObserver extends AbstractObserver{
public HexObserver(Subject subject) {
this.subject = subject;
// 加入到观察者队列
this.subject.addObserver(this);
}
@Override
public void subscribe() {
System.out.println("hex string :" + Integer.toHexString(this.subject.getPublish()));
}
}
3.主体类;
import java.util.ArrayList;
import java.util.List;
/**
* 3.主体对象,被观察对象
* @author 程就人生
* @Date
*/
public class Subject {
// 观察者集合
private List<AbstractObserver> observerList = new ArrayList<AbstractObserver>();
private int publish;
/**
* 添加观察对象
* @param observer
*/
public void addObserver(AbstractObserver observer) {
observerList.add(observer);
}
/**
* 状态改变时,通知所有的观察者
* @param state
*/
public void setPublish(int publish) {
this.publish = publish;
noticeAllObserverlist();
}
public int getPublish() {
return publish;
}
/**
* 通知所有观察者
*/
private void noticeAllObserverlist() {
observerList.forEach(observer->{
observer.subscribe();
});
}
}
4.测试代码;
public static void main(String[] argo){
// 创建主体
Subject subject = new Subject();
// 观察者进行事件订阅
new BinaryObserver(subject);
new HexObserver(subject);
// 主体发布
subject.setPublish(5);
subject.setPublish(20);
}
运行结果:
binary string :101
hex string :5
binary string :10100
hex string :14
这段代码的意思是:主体对象输入一个10进制数据,二进制观察者和十六进制观察者接收到通知后会把这个数据转变为对应的进制。
在我们的java.util包中已经存在这么两个类,一个是观察者接口:Observer,一个是可观察的类:Observable,我们把上面的代码调整一下。
1.主体对象编码;
import java.util.Observable;
import java.util.Observer;
/**
* 2.1 二进制观察者 实现了 观察者接口
* @author 程就人生
* @Date
*/
public class BinaryObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
Subject subject = (Subject) o;
System.out.println("binary string :" + Integer.toBinaryString(subject.getPublish()));
}
}
import java.util.Observable;
import java.util.Observer;
/**
* 2.2 十六进制观察者 实现了 观察者接口
* @author 程就人生
* @Date
*/
public class HexObserver implements Observer{
@Override
public void update(Observable o, Object arg) {
Subject subject = (Subject) o;
System.out.println("hex string :" + Integer.toHexString(subject.getPublish()));
}
}
2.观察者实现类;
import java.util.Observable;
import java.util.Observer;
/**
* 2.1 二进制观察者 实现了 观察者接口
* @author 程就人生
* @Date
*/
public class BinaryObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
Subject subject = (Subject) o;
System.out.println("binary string :" + Integer.toBinaryString(subject.getPublish()));
}
}
import java.util.Observable;
import java.util.Observer;
/**
* 2.2 十六进制观察者 实现了 观察者接口
* @author 程就人生
* @Date
*/
public class HexObserver implements Observer{
@Override
public void update(Observable o, Object arg) {
Subject subject = (Subject) o;
System.out.println("hex string :" + Integer.toHexString(subject.getPublish()));
}
}
3.测试代码;
public static void main(String[] argo){
// 创建主体
Subject subject = new Subject();
// 观察者进行事件订阅
subject.addObserver(new BinaryObserver());
subject.addObserver(new HexObserver());
// 主体发布
subject.setPublish(5);
subject.setPublish(20);
}
测试结果:
hex string :5
binary string :101
hex string :14
binary string :10100
代码分析:我们自己写的,与java.util的区别,就在于观察者集合的存放位置不一样,java.util封装的更完善一些。
最后总结
观察者模式,又称发布订阅模式,是我们项目中使用较多的一种设计模式。除了JDK,还有其他的架包也使用了观察者模式。你还能想到哪些用到观察者模式的场景呢?你还能想到哪些包含观察者模式的架包吗?
网友评论