观察者模式 观察者模式 指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。
属于行为型模式
类图
ISubject 1 2 3 4 5 6 7 8 public interface ISubject <E > { boolean attach (IObserver<E> observer) ; boolean detach (IObserver<E> observer) ; void notify (E event) ; }
ConcreteSubject 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 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 1 2 3 4 public interface IObserver <E > { void update (E event) ; }
ConcreteObserver 1 2 3 4 5 6 public class ConcreteObserver <E > implements IObserver <E > { @Override public void update (E event) { System.err.println("receive event " + event); } }
DemoTest 1 2 3 4 5 6 7 8 9 10 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来模拟一个简单的场景;
Blog 被观察对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 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 学生类 被通知对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 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; } @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 测试 1 2 3 4 5 6 7 8 9 10 11 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); } }
测试结果 1 2 3 4 5 6 7 小明 在 blog 提交了问题 : 观察者模式是什么? ****************** John看到了 小明 的问题 问题是: 观察者模式是什么? ****************** Tom看到了 小明 的问题 问题是: 观察者模式是什么?
基于Guava实现观察者模式 Student 被观察对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 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 被通知对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 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 测试类 1 2 3 4 5 6 7 8 9 10 11 12 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" )); } }
测试结果 1 2 student invoke method + Student{name='xuesheng' } teacher invoke method + Teacher{name='teacher' }
观察者模式使用场景 1、当一个抽象模型包含两个方面内容,其中一个方面依赖另一个方面 2、其他一个或多个对象的变化依赖另一个对象的变化 3、实现类似广播机制的功能,无需知道具体收听者,只需要广播。系统中感兴趣的对象会自动接口该广播 4、多层级嵌套机制,形成一种链式出发机制,是的时间具备跨域(跨越两种观察者类型)通知
观察者模式优点✅ 1、降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。 2、目标与观察者之间建立了一套触发机制。
观察者模式缺点 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。