什么是观察者模式
定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
使用场景
- 解耦:当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
- 可扩展性:当一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变。
- 当一个对象必须通知其他对象,而它又不能假定其它对象是谁。换言之,你不希望这些对象是紧密耦合。
观察者模式的结构
image.png
Subject(目标)
当它的状态发生改变时,向它的各个观察者发出通知。
Observer(观察者)
实现Observer的更新接口以使自身状态与目标状态一致。
观察者模式的优缺点
优点
- 目标和观察者的抽象耦合:一个目标所知道仅仅是它有一系列观察者,每个都符合抽象的Observer类的简单接口。
- 支持广播通信:目标对象并不关心到底有多少对象对自己感兴趣,它唯一的职责就是通知它的各观察者。
缺点: - 意外更新:如果依赖准则的定义和维护不当,常常会引起错误的更新,这种错误通常很难捕获。
观察者模式的实现
先来看一个典型的实例:
/**
* 定义抽象的目标类
*
* @author tomxin
* @date 2018-11-18
* @since v1.0.0
*/
public interface Subject {
/**
* 发送消息
*/
void publish(String message);
}
/**
* 定义一个具体的目标类
*
* @author tomxin
* @date 2018-11-18
* @since v1.0.0
*/
public class ConcreteSubject implements Subject {
List<Observer> observerList = new ArrayList<>();
/**
* 添加观察者
*
* @param observer
*/
public void addObserver(Observer observer) {
observerList.add(observer);
}
/**
* 发送消息
*
* @param message
*/
@Override
public void publish(String message) {
for (Observer observer : observerList) {
observer.handler(message);
}
}
}
/**
* 自定义观察者
*
* @author tomxin
* @date 2018-11-18
* @since v1.1.0
*/
public interface Observer {
/**
* 处理消息
*
* @param message
*/
void handler(String message);
}
/**
* 创建实例观察者
*
* @author tomxin
* @date 2018-11-18
* @since v1.0.0
*/
public class ConcreteObserver implements Observer {
/**
* 处理消息
*
* @param message
*/
@Override
public void handler(String message) {
System.out.println(this.getClass());
System.out.println(message);
}
}
/**
* 创建实例观察者
*
* @author tomxin
* @date 2018-11-18
* @since v1.0.0
*/
public class ConcreteObserver1 implements Observer {
/**
* 处理消息类
*
* @param message
*/
@Override
public void handler(String message) {
System.out.println(this.getClass() + ",message : " + message);
}
}
/**
* Main函数
*
* @author tomxin
* @date 2018-11-18
* @since v1.0.0
*/
public class ObserverMain {
public static void main(String[] args) {
// 实例化目标类
Subject subject = new ConcreteSubject();
// 定义观察者
Observer observer1 = new ConcreteObserver();
Observer observer2 = new ConcreteObserver1();
((ConcreteSubject) subject).addObserver(observer1);
((ConcreteSubject) subject).addObserver(observer2);
// 发送消息
subject.publish("notify message");
}
}
Observer + Mediator 模式结合实现观察者模式,实现Observer与Mediator解耦。
/**
* 观察者接口
*
* @author tomxin
* @date 2018-11-18
* @since v1.0.0
*/
public interface MediatorObserver {
/**
* 处理消息的接口
*
* @param message
*/
void handler(String message);
}
/**
* @author tomxin
* @date 2018-11-18
* @since v1.0.0
*/
public class ObserverInstance implements MediatorObserver {
public ObserverInstance() {
// 在构造函数中
MediatorInstance.register(this);
}
/**
* 处理消息
*
* @param message
*/
@Override
public void handler(String message) {
System.out.println(message);
}
}
/**
* 定义目标类
*
* @author tomxin
* @date 2018-11-18
* @since v1.0.0
*/
public class MediatorSubject {
/**
* 消息通知
*
* @param message
*/
public void notify(String message) {
MediatorInstance.publish(message);
}
}
/**
* 中介者实体类
*
* @author tomxin
* @date 2018-11-18
* @since v1.0.0
*/
public class MediatorInstance {
/**
* 观察者列表
*/
private static Set<Object> observerList = new HashSet<>(16);
/**
* 注册观察者
*
* @param observer
*/
public static void register(Object observer) {
observerList.add(observer);
}
/**
* 发送消息
*
* @param message
*/
public static void publish(String message) {
try {
for (Object observer : observerList) {
Class<?> observerClazz = observer.getClass();
Class[] classes = new Class[1];
classes[0] = String.class;
Method method = observerClazz.getMethod("handler", classes);
Object result = method.invoke(observer, message);
}
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
/**
* Main方法
*
* @author tomxin
* @date 2018-11-17
* @since v1.0.0
*/
public class MediatorObserverMain {
public static void main(String[] args) {
// 实例化观察者
ObserverInstance observerInstance = new ObserverInstance();
// 实例化目标类
MediatorSubject mediatorSubject = new MediatorSubject();
// 发送消息通知
mediatorSubject.notify("message");
}
}
有兴趣的同学,可以看一下Guava中EventBus的实现。
网友评论