观察者模式
在处理类之间的多对一的依赖关系时,观察者设计模式应运而生了,它的出现实现了代码的瘦身,类之间的解耦,本文分三部分:
- 非观察者模式的多对一的依赖处理
- 观察者模式对多对一依赖处理的优化
- Java内置的观察者
假设场景: 前端用户向后端服务器发送不同的请求,后端的Selector区的分不同的请求,回调不同的Handler处理请求, 下面的示例代码
非观察者
当Selector发现数据改变时,想要回调Handler的方法的前提是它要维护一个Handler的引用, 我们在构造函数中传递进去
@Data
public class Selector {
private String username;
private String password;
private Handler1 currentConditions;
public Selector(Handler1 currentConditions) {
this.currentConditions = new Handler1();
}
public void datachange() {
currentConditions.update(getUsername(),getPassword());
}
// 添加假数据
public void setData(String username,String password){
this.username=username;
this.password=password;
datachange();
}
}
Handkler 的成员变量和Selector一样, 同时真正干活的人是handler, 它里面只有干活的方法以及承载数据的字段, 干活的方法会被回调, 字段由Selector负责初始化
public class Handler1 {
private String username;
private String password;
public void update( String username, String password){
this.username=username;
this.password=password;
display();
}
public void display(){
System.out.println("Handler1 : username"+ username);
System.out.println("Handler1 : password"+username);
}
}
测试:
public class text {
public static void main(String[] args) {
Handler1 currentConditions = new Handler1();
Selector Data = new Selector(currentConditions);
Data.setData("张三","123");
}
}
上面的设计方法实现了,当Selector发现新的数据改变时,回调指定的handler的需求,但是缺点很快就暴露出来, Handler引用以构造方法的形式在Selector维护,如果有100个handler, 是不是意味着Selector的构造函数重载100份?
观察者模式
观察者解决了上面的问题,在观察者模式中有两个角色的划分,1.SubJect 2.Observer, 其中 SubJect负责回调Observer提供的方法处理数据, Observer就是观察者,伺机而动, 它之所以能够实现两者的解耦,实现代码的瘦身,精华就是在Subject的构造函数不再维护单一的某一个Observer的引用,而是一个泛型是为Observer类型的集合, 为了防止把非观察者的对象添加到集合中, 故 在原有的基础上,向上进行了一层抽象,把Subject和Observer设计成接口,Subject提供了注册/移除/通知观察者的方法,通知哪个方法呢? 于是Observer接口中提供了需要被回调的抽象方法, 做完这层封装之后,就有了这个观察者体系, 所有的观察者必须实现Observer接口,重写它的方法,任何回调观察者的类,也必须实现Subject,重写它的方法
实例代码:
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver();
}
public interface Observer {
public void update(String m,String p);
}
Subject的实现类:
@Data
public class Selector implements Subject {
private String username;
private String password;
private ArrayList<Observer> list;
public Selector() {
this.list = new ArrayList<Observer>();
}
// 添加假数据
public void setData( String username, String password){
this.username=username;
this.password=password;
}
@Override
public void registerObserver(Observer o) {
list.add(o);
}
@Override
public void removeObserver(Observer o) {
list.remove(o);
}
@Override
public void notifyObserver() {
list.forEach(s->s.update(getPassword(),getUsername()));
}
}
Observer的实现:
public class Handler1 implements Observer {
private String username;
private String password;
@Override
public void update( String username,String password){
this.username=username;
this.password=password;
display();
}
public void display(){
System.out.println(" Handler1 "+ username);
System.out.println(" Handler1 "+password);
}
}
测试:
public class text {
public static void main(String[] args) {
Handler1 secondConditions = new Handler1();
Selector Data = new Selector();
// 注册观察者
Data.registerObserver(secondConditions);
Data.setData("张三","123");
Data.notifyObserver();
}
}
我们自己实现的观察者函数回调的特性: : 虽然实现我们一开始的需求,但是可以看到,数据是在Subject
端进行初始化的, 并没有传递到观察端,由观察者自主分配数据
java内置的观察者
java内置的观察中同样分为两种角色,1.Obserable 2.Observer 其中Observer是观察者,同样不变的是,他是个接口
但是: Obserable是一个抽象类, java为我们实现了 注册/移除,通知的方法, 在不允许多继承的java中,抽象类是有缺点的,这使得当前类不能再继承其他类
此外: 相对于我们自定义的观察者, 它做到了把数据传递到 观察者客户端,任由观察者自主的分配这些数据
如何使用:
对于Obserable来说, 继承他
- 由于java实现了主要的方法, 我们只关注如何使用这几个方法就行了
- 1: 在回调之前 , 必须先使用
this.setChanged();
否则信息不会通知到观察者 - 2: 通知的方法
this.notifyObservers(Object obj));
@Data
public class Selector extends Observable {
private String username;
private String password;
// 添加假数据
public void setData( String username, String password) {
this.username = username;
this.password = password;
datachange();
}
// 当信息更改, 就推送
public void datachange() {
// todo 加上这一条,当有信息改变时, 就执行
this.setChanged();
// 通知时,把信息同步推送给观察者
this.notifyObservers(new Data(getUsername(),getPassword()));
}
@lombok.Data
public class Data {
private String username;
private String password;
public Data( String username, String password) {
this.username = username;
this.password = password;
}
}
}
观察者: 继承Observer, 重写它被回调的方法
public class Handler1 implements Observer {
private String username;
private String password;
@Override
public void update(Observable observable, Object arg0) {
this.password = ((Selector.Data) (arg0)).getPassword();
this.username = ((Selector.Data) (arg0)).getUsername();
display();
}
public void display() {
System.out.println("Handler1 : " + username);
System.out.println("Handler1 : " + password);
}
}
测试
public class text {
public static void main(String[] args) {
Handler1 handler1 = new Handler1();
Selector weatherData = new Selector();
// 先注册的观察者,后执行
weatherData.addObserver(handler1);
weatherData.setData("张三","123");
}
}