定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。如微博中一个明星发了一个消息,所有关注的用户都会看到这条消息。
观察者接口
/** * 观察者接口 */ public interface Observer { void update(Subject subject); }
具体观察者
/** * 观察者实现 */ public class ConcreteObserver implements Observer { @Override public void update(Subject subject) { ConcreteSubject concreteSubject = (ConcreteSubject) subject; System.out.println("ConcreteObserver," + concreteSubject.getSubjectState()); } }
另一个观察者
/** * 观察者实现 */ public class ConcreteObserver2 implements Observer { @Override public void update(Subject subject) { ConcreteSubject concreteSubject = (ConcreteSubject) subject; System.out.println("ConcreteObserver2," + concreteSubject.getSubjectState()); } }
目标对象
import java.util.ArrayList; import java.util.List; public class Subject { private List<Observer> observers = new ArrayList<>(); /** * 注册观察者 */ public void attach(Observer observer) { observers.add(observer); } /** * 删除观察者 */ public void detach(Observer observer) { observers.remove(observer); } /** * 通知所有观察者 */ protected void notifyObservers() { for (Observer observer : observers) { observer.update(this); } } }
具体的目标对象
public class ConcreteSubject extends Subject { private String subjectState; public String getSubjectState() { return subjectState; } public void setSubjectState(String subjectState) { this.subjectState = subjectState; notifyObservers(); } }
客户端
public class Client { public static void main(String[] args) { ConcreteSubject subject = new ConcreteSubject(); subject.attach(new ConcreteObserver()); subject.attach(new ConcreteObserver2()); subject.setSubjectState("test"); } }
其实java中已经提供了 Observer 接口和 Observable 目标类,我们只需要在此基础上实现就可以了。
import java.util.Observable; import java.util.Observer; /** * 观察者实现 */ public class ConcreteObserver implements Observer { @Override public void update(Observable o, Object arg) { ConcreteSubject concreteSubject = (ConcreteSubject) o; System.out.println("ConcreteObserver," + concreteSubject.getSubjectState()); } }
import java.util.Observable; import java.util.Observer; /** * 观察者实现 */ public class ConcreteObserver2 implements Observer { @Override public void update(Observable o, Object arg) { ConcreteSubject concreteSubject = (ConcreteSubject) o; System.out.println("ConcreteObserver2," + concreteSubject.getSubjectState()); } }
具体的目标对象
import java.util.Observable; public class ConcreteSubject extends Observable { private String subjectState; public String getSubjectState() { return subjectState; } public void setSubjectState(String subjectState) { this.subjectState = subjectState; setChanged(); notifyObservers(); } }
客户端
public class Client { public static void main(String[] args) { ConcreteSubject subject = new ConcreteSubject(); subject.addObserver(new ConcreteObserver()); subject.addObserver(new ConcreteObserver2()); subject.setSubjectState("test"); } }
观察者模式有两种实现方式,推模型和拉模型。
根据上面的描述,我们上面的实现就是拉模型,下面我们实现一下推模型,基于我们自己定义的Observer接口。
/** * 观察者接口 */ public interface Observer { void update(String content); }
具体观察者
/** * 观察者实现 */ public class ConcreteObserver implements Observer { @Override public void update(String content) { System.out.println("ConcreteObserver," + content); } }
目标对象
public class Subject { private List<Observer> observers = new ArrayList<>(); /** * 注册观察者 */ public void attach(Observer observer) { observers.add(observer); } /** * 删除观察者 */ public void detach(Observer observer) { observers.remove(observer); } /** * 通知所有观察者 */ protected void notifyObservers(String content) { for (Observer observer : observers) { observer.update(content); } } }
具体目标对象
public class ConcreteSubject extends Subject { private String subjectState; public void setSubjectState(String subjectState) { this.subjectState = subjectState; notifyObservers(subjectState); } }
主要的变化在于update方法的参数由Subject(目标对象本身)变成了content(目标对象的详细信息)。
import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; public class TestEventBus { public static void main(String[] args) { EventBus eventBus = new EventBus(); eventBus.register(new SimpleEventListener()); eventBus.post("this is a test event"); eventBus.post(12); } static class SimpleEventListener { @Subscribe public void test(String event) { System.out.println("received1 the event from eventbus: " + event); } @Subscribe public void test2(Integer event) { System.out.println("received2 the event from eventbus: " + event); } } }
输出结果为
received1 the event from eventbus: this is a test event received2 the event from eventbus: 12
使用Subscribe注解来注册观察者,通过参数类型来区分不同的目标对象,如String类型,Integer类型,使用post方法发布一条信息,找到这条消息的类型所对应的观察者列表,通知它们,通过反射执行方法。
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; public class TestApplicationEvent { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class); context.publishEvent(new OrderSuccessEvent(new Object())); } public static class OrderSuccessEvent extends ApplicationEvent { public OrderSuccessEvent(Object source) { super(source); } } @Configuration public static class BeanConfig { @Bean public SmsService smsService() { return new SmsService(); } @Bean public SmsService2 smsService2() { return new SmsService2(); } } public static class SmsService implements ApplicationListener<OrderSuccessEvent> { @Override public void onApplicationEvent(OrderSuccessEvent event) { System.out.println("SmsService " + event.getSource()); } } public static class SmsService2 implements ApplicationListener<OrderSuccessEvent> { @Override public void onApplicationEvent(OrderSuccessEvent event) { System.out.println("SmsService2 " + event.getSource()); } } }
和guava中EventBus使用方法类似,通过ApplicationEvent的具体类型来区分不同的目标对象,publishEvent方法发布一个事件,从IOC容器中查找所有支持此event类型的观察者列表,通知它们。
观察者模式的本质是触发联动。在程序运行期间动态的注册和删除观察者,可以变相的实现添加和删除某些功能处理。
大战设计模式【2】—— 观察者模式
设计模式的征途—15.观察者(Observer)模式
设计模式(十八)——观察者模式(JDK Observable源码分析)
观察者模式(Observer模式)详解
Spring事件监听机制
研磨设计模式-书籍