2观察者模式
观察者模式
观察者模式(Observer Pattern)也被发布订阅模式,它是一种在项目中经常使用的模式。
1观察者模式的定义
观察者模式的英文原文:
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
观察者模式具有4个角色:
- 抽象主题角色:该角色又被称为“被观察者”,可以增加和删除观察者对象。
- 抽象观察者角色:该角色为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。
- 具体主题角色:该角色又称为“具体被观察者”,它将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
- 具体观察者角色:该角色实现抽象观察者所要求的更新接口,以便使自身的状态与主题的状态相协调。
创建抽象主题Subject类
Subject.java
package com.eric.行为型模式_Part2.观察者模式.引例;
/**
* @author Eric
* @ProjectName my_design_23
* @description 抽象主题
* @CreateTime 2020-12-11 13:23:42
*/
public interface Subject {
//登记一个新的观察者
public void attach(Observer obs);
//删除一个登记过的观察者
public void detach(Observer obs);
//通知所有登记过的观察者对象
public void notifyObserver();
}
创建抽象观察者
Observer.java
package com.eric.行为型模式_Part2.观察者模式.引例;
/**
* @author Eric
* @ProjectName my_design_23
* @description 抽象观察者
* @CreateTime 2020-12-11 13:25:54
*/
public interface Observer {
//更新方法
public void update();
}
创建具体主题实现类
ConcreteSubject.java
package com.eric.行为型模式_Part2.观察者模式.引例;
import java.util.Enumeration;
import java.util.Vector;
/**
* @author Eric
* @ProjectName my_design_23
* @description 具体主题
* @CreateTime 2020-12-11 13:27:01
*/
public class ConcreteSubject implements Subject {
private Vector<Observer> observerVector = new Vector<>();
//登记一个新观察者
@Override
public void attach(Observer obs) {
observerVector.add(obs);
}
//删除一个登记过的观察者
@Override
public void detach(Observer obs) {
observerVector.remove(obs);
}
//通知所有登记过的观察者对象
@Override
public void notifyObserver() {
for (Observer observer : observerVector) {
observer.update();
}
}
//返回观察者集合的Enumeration对象
public Enumeration<Observer> observers(){
return observerVector.elements();
}
//业务方法,改变状态
public void change(){
this.notifyObserver();
}
}
创建观察者实现类
ConcreteObserver.java
package com.eric.行为型模式_Part2.观察者模式.引例;
/**
* @author Eric
* @ProjectName my_design_23
* @description 具体观察者
* @CreateTime 2020-12-11 13:33:20
*/
public class ConcreteObserver implements Observer {
//实现更新方法
@Override
public void update() {
System.out.println("收到通知,并进行处理!");
}
}
创建测试类
Client.java
package com.eric.行为型模式_Part2.观察者模式.引例;
/**
* @author Eric
* @ProjectName my_design_23
* @description 测试类
* @CreateTime 2020-12-11 13:34:34
*/
public class Client {
public static void main(String[] args) {
//创建一个主体对象
ConcreteSubject concreteSubject = new ConcreteSubject();
//创建一个观察者
ConcreteObserver concreteObserver = new ConcreteObserver();
//登记观察者
concreteSubject.attach(concreteObserver);
//改变状态
concreteSubject.change();
}
}
测试结果
2观察者模式的应用
a.观察者模式的优缺点
观察者模式的优点
- 观察者和被观察者之间是抽象耦合。被观察者角色所知道的只是一个具体观察者集合,每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体的观察者,它只知道他们都有一个共同的接口。由于被观察者和被观察者没有紧密的耦合在一起,因此他们可以属于不同的抽象化层次,且都非常容易扩展。
- 支持广播通信。被观察者会向所有登记过的观察者发出通知,这就是一个触发机制,形成一个触发链。
观察者模式的缺点
- 如果一个主题有多个直接或间接的观察者,则通知所有的观察者会花费很多时间,且开发和调试都比较复杂。
- 如果在主题之间有循环依赖,被观察者会触发他们之间进行循环调用,导致系统崩溃。在使用观察者模式时要特别注意。
- 如果对观察者的通知是通过另外的线程进行异步投递,系统必须保证投递的顺序执行。
- 虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有提供相应的机制使观察者知道所观察的对象是如何发生变化。
b观察者模式的应用场景
- 关联行为场景
- 事件多级触发场景
- 跨系统的消息交换场景,如消息队列的处理机制。
c观察者模式的注意事项
- 广播链的问题。一个观察者可以有双重身份,即是观察者也是被观察者,广播链一旦建立,逻辑就比较复杂,可维护性非常差。一般在一个观察者模式中最多出现一个对象,既是观察者又是被观察者,这样消息最多转发一次(传递两次),较易控制。
- 异步处理的问题。异步处理就要考虑线程安全和队列问题。
注意:观察者广播链和责任链模式的最大区别就是观察者广播链在广播的过程中,消息是随时更改的,是由相邻的两个节点协商的消息结构;而责任链模式在消息传递过程中,消息是保持不变的,如果要改变,也只有在原有消息上进行修正。
3观察者模式的实例
使用观察者模式模拟按钮控件的事件处理机制。
ClickableObserver.java
package com.eric.行为型模式_Part2.观察者模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 单击事件观察者接口
* @CreateTime 2020-12-11 18:25:50
*/
public interface ClickableObserver {
//发生单击事件时的操作
void clicked(Clickable clickable);
}
创建单击接口
Clickable.java
package com.eric.行为型模式_Part2.观察者模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 点击接口
* @CreateTime 2020-12-11 18:23:45
*/
public interface Clickable {
//单击
void click();
//添加单击事件的观察者
void addClickableObserver(ClickableObserver clickableObserver);
//移除单击事件的观察者
void removeClickableObserver(ClickableObserver clickableObserver);
}
创建Button并实现单击接口
Button.java
package com.eric.行为型模式_Part2.观察者模式.例1;
import java.util.ArrayList;
import java.util.List;
/**
* @author Eric
* @ProjectName my_design_23
* @description 按钮控件
* @CreateTime 2020-12-11 18:46:23
*/
public class Button implements Clickable {
//存储注册过的单击事件观察者
List<ClickableObserver> observers = new ArrayList<>();
//按钮信息
String color;//颜色
int x,y;
@Override
public void click() {
System.out.println("单击了按钮...");
//执行所有观察者的事件处理方法
for (int i = observers.size()-1; i >= 0; i--) {
observers.get(i).clicked(this);
}
}
@Override
public void addClickableObserver(ClickableObserver clickableObserver) {
observers.add(clickableObserver);
}
@Override
public void removeClickableObserver(ClickableObserver clickableObserver) {
observers.remove(clickableObserver);
}
@Override
public String toString() {
return "按钮颜色:"+color+",坐标:("+x+","+y+")";
}
}
创建ClickableObserver的3个实现类
ChangeColorObserver.java
package com.eric.行为型模式_Part2.观察者模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 修改按钮颜色的观察者
* @CreateTime 2020-12-11 18:52:26
*/
public class ChangeColorObserver implements ClickableObserver {
@Override
public void clicked(Clickable clickable) {
Button button = (Button) clickable;
button.color = "红色";
}
}
ChangeCoordinateObserver.java
package com.eric.行为型模式_Part2.观察者模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 修改按钮坐标的观察者
* @CreateTime 2020-12-11 18:54:07
*/
public class ChangeCoordinateObserver implements ClickableObserver {
@Override
public void clicked(Clickable clickable) {
Button button = (Button) clickable;
button.x = 100;
button.y = 90;
}
}
OtherObserver.java
package com.eric.行为型模式_Part2.观察者模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 其他业务的处理类
* @CreateTime 2020-12-11 18:55:21
*/
public class OtherObserver implements ClickableObserver {
@Override
public void clicked(Clickable clickable) {
System.out.println("执行其他操作中...");
}
}
创建测试类
Client.java
package com.eric.行为型模式_Part2.观察者模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 测试类
* @CreateTime 2020-12-11 18:57:01
*/
public class Client {
public static void main(String[] args) {
Button button = new Button();
button.color="白色";
button.x=0;
button.y=0;
//为按钮添加观察者
button.addClickableObserver(new ChangeColorObserver());
button.addClickableObserver(new ChangeCoordinateObserver());
button.addClickableObserver(new OtherObserver());
button.click();
System.out.println(button);
}
}
测试结果
只要你不停下来,慢一点也没关系。