观察者模式

# 观察者模式 ## 观察者模式 指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。 属于行为型模式 ## 类图 ![](https://oscimg.oschina.net/oscnet/up-cc1738bd0907f74ecc63783f3282a9a1aec.png) ### ISubject ```text public interface ISubject<E> { boolean attach(IObserver<E> observer); boolean detach(IObserver<E> observer); void notify(E event); } ``` ### ConcreteSubject ```text public class ConcreteSubject<E> implements ISubject<E> { private List<IObserver<E>> observers = new ArrayList<>(); @Override public boolean attach(IObserver<E> observer) { if (this.observers.contains(observer)) { return false; } observers.add(observer); return true; } @Override public boolean detach(IObserver<E> observer) { return this.observers.remove(observer); } @Override public void notify(E event) { for (IObserver observer : observers) { observer.update(event); } } } ``` ### IObserver ```text public interface IObserver<E> { void update(E event); } ``` ### ConcreteObserver ```text public class ConcreteObserver<E> implements IObserver<E> { @Override public void update(E event) { System.err.println("receive event " + event); } } ``` ### DemoTest ```text public class DemoTest { public static void main(String[] args) { ISubject<String> subject = new ConcreteSubject<String>(); subject.attach(new ConcreteObserver<String>()); subject.attach(new ConcreteObserver<String>()); subject.attach(new ConcreteObserver<String>()); subject.notify("test"); } } ``` ## JDK实现观察者模式 > 比如有一个博客系统提供了问题社区,一个人提出问题,会有其他人收到这个消息;我们使用JDK来模拟一个简单的场景; ![](https://oscimg.oschina.net/oscnet/up-a268997531d268d3ff748a45b29adc83031.png) ### Blog 被观察对象 ```text public class Blog extends Observable { private Blog() { } private static final Blog blog = new Blog(); private String name = "IBLi Blog"; public static Blog getInstance() { return blog; } public void question(Question question) { System.out.println(question.getUserName() + " 在 blog 提交了问题 : " + question.getContent()); setChanged(); notifyObservers(question); } } ``` ### Question ```text public class Question { private String userName; private String content; public Question(String userName, String content) { this.userName = userName; this.content = content; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } ``` ### Student 学生类 被通知对象 ```text public class Student implements Observer { private String name; public Student(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } /** * This method is called whenever the observed object is changed. An * application calls an <tt>Observable</tt> object's * <code>notifyObservers</code> method to have all the object's * observers notified of the change. * * @param o the observable object. * @param arg an argument passed to the <code>notifyObservers</code> */ @Override public void update(Observable o, Object arg) { Blog blog = (Blog) o; Question question = (Question) arg; System.out.println("******************"); System.out.println(this.name + " 看到了 " + question.getUserName() + " 的问题 \n" + "问题是: " + question.getContent()); } } ``` ### Client 测试 ```text public class Client { public static void main(String[] args) { Blog blog = Blog.getInstance(); blog.addObserver(new Student("Tom")); blog.addObserver(new Student("John")); Question question = new Question("小明","观察者模式是什么?"); blog.question(question); } } ``` ### 测试结果 ```text 小明 在 blog 提交了问题 : 观察者模式是什么? ****************** John看到了 小明 的问题 问题是: 观察者模式是什么? ****************** Tom看到了 小明 的问题 问题是: 观察者模式是什么? ``` ## 基于Guava实现观察者模式 ### Student 被观察对象 ```text public class Student { private String name; public Student(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + '}'; } @Subscribe public void Observer(Student str) { System.err.println("student invoke method + " + str.toString()); } } ``` ### Teacher 被通知对象 ```text public class Teacher { private String name; public Teacher(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Teacher{" + "name='" + name + '\'' + '}'; } @Subscribe public void Observer(Teacher str) { System.err.println("teacher invoke method + " + str.toString()); } } ``` ### Client 测试类 ```text public class Client { public static void main(String[] args) { EventBus eventBus = new EventBus(); Student student = new Student("Ibli"); Teacher teacher = new Teacher("laoshi"); eventBus.register(student); eventBus.register(teacher); eventBus.post(new Student("xuesheng")); eventBus.post(new Teacher("teacher")); } } ``` ### 测试结果 ```text student invoke method + Student{name='xuesheng'} teacher invoke method + Teacher{name='teacher'} ``` ## 观察者模式使用场景 1、当一个抽象模型包含两个方面内容,其中一个方面依赖另一个方面 2、其他一个或多个对象的变化依赖另一个对象的变化 3、实现类似广播机制的功能,无需知道具体收听者,只需要广播。系统中感兴趣的对象会自动接口该广播 4、多层级嵌套机制,形成一种链式出发机制,是的时间具备跨域(跨越两种观察者类型)通知 ## 观察者模式优点✅ 1、降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。 2、目标与观察者之间建立了一套触发机制。 ## 观察者模式缺点 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。