又叫做发布-订阅模式
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新
观察者模式中的角色
Subject:抽象主题(抽象被观察者)抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
ConcreteSubject:具体主题(具体被观察者)该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
Observer:抽象观察者,定义更新接口,使得在得到主题更改通知时更新自己。
ConcreteObject:具体观察者,在得到主题更改通知时更新自身的状态。
观察者模式结构图解
Demo:新闻社 + 新闻社订阅者
//抽象观察者
abstract public class Observer {
public abstract void update(String msg);
}
//具体观察者
public class NewsSubUser extends Observer {
private String username;
public NewsSubUser(String name){
this.username = name;
}
public void update(String msg) {
System.out.println("尊敬的["+username+"]用户,您有一条新闻:"+msg);
}
}
//抽象被观察者
abstract public class Subject {
//新增订阅者
public abstract void add(Observer observer);
//移除订阅者
public abstract void remove(Observer observer);
//通知订阅者
public abstract void notifyUser(String msg);
}
//具体被订阅者(新闻社)
public class NewsOffice extends Subject {
//存放订阅者
private List<Observer> list = new ArrayList<Observer>();
//添加订阅者
public void add(Observer observer) {
list.add(observer);
}
//移除订阅者
public void remove(Observer observer) {
list.remove(observer);
}
//通知订阅者
public void notifyUser(String msg) {
//遍历订阅者 依次通知
for(Observer observer : list){
observer.update(msg);
}
}
}
//测试方法
public static void main(String[] args){
//订阅者
NewsSubUser user = new NewsSubUser("cllblogs");
NewsSubUser user2 = new NewsSubUser("cll");
NewsSubUser user3 = new NewsSubUser("Mr丶C");
//新闻社
NewsOffice news = new NewsOffice();
//添加订阅者
news.add(user);
news.add(user2);
news.add(user3);
//提示订阅者有新的消息
news.notifyUser("2018中国进口博览会开幕式");
}
输出打印结果:
尊敬的[cllblogs]用户,您有一条新闻:2018中国进口博览会开幕式
尊敬的[cll]用户,您有一条新闻:2018中国进口博览会开幕式
尊敬的[Mr丶C]用户,您有一条新闻:2018中国进口博览会开幕式
观察者模式优缺点
优点:观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
缺点:这种依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。
事件委托弥补观察者模式的缺点
//定义一个事件类
public class Event {
//要执行方法的对象
private Object object;
//要执行方法的名称
private String methodName;
//要执行方法的参数
private Object[] params;
//参数类型
private Class[] paramTypes;
public Event(){}
//初始化构造
public Event(Object object,String methodName,Object ... args){
this.object = object;
this.methodName = methodName;
this.params = args;
assembleParamType(this.params);
}
//方法执行类
public void invoke() throws Exception {
Method method = object.getClass().getMethod(this.methodName,this.paramTypes);
if(null == method){
return;
}
method.invoke(this.object,this.params);
}
//组装参数类型
private void assembleParamType(Object[] params) {
this.paramTypes = new Class[params.length];
for (int i = 0; i < params.length; i++) {
paramTypes[i] = params[i].getClass();
}
}
}
// EventHandler类 Event事件的载体 添加Event 同时提供执行所有Event的方法
public class EventHandler {
//存储事件容器
private List<Event> events;
public EventHandler(){
events = new ArrayList<Event>();
}
//添加对象要执行的事件以及对应的参数
public void addEvent(Object object,String methodName,Object ... args){
events.add(new Event(object,methodName,args));
}
//通知事件执行指定的方法
public void notifyM() throws Exception {
for(Event event : events){
event.invoke();
}
}
}
// 抽象通知类 1.增加监听者 2.通知监听者执行事件
public abstract class Notifier {
public EventHandler getEventHandler() {
return eventHandler;
}
public void setEventHandler(EventHandler eventHandler) {
this.eventHandler = eventHandler;
}
private EventHandler eventHandler = new EventHandler();
//增加监听者
public abstract void addListener(Object object,String methodName,Object ... args);
//通知监听者执行事件
public abstract void notifyM();
}
// 具体通知者 继承抽象通知者 并实现其两个抽象方法
public class TTNotifier extends Notifier {
//添加监听者
public void addListener(Object object, String methodName, Object... args) {
System.out.println("添加新的监听者...");
this.getEventHandler().addEvent(object,methodName,args);
}
//通知监听者
public void notifyM() {
System.out.println("通知监听者执行事件...");
try {
this.getEventHandler().notifyM();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 具体的监听者
public class TTListenerA {
//用户名
private String username;
public TTListenerA(String username){
this.username = username;
}
//订阅新闻
public void subNews(){
System.out.println("我订阅了TT新闻...");
}
//查看最新新闻
public void seeNewNews(String news){
System.out.println("尊敬的["+username+"]用户,您有一条新闻:"+news);
}
}
// 测试类
public class Test {
public static void main(String[] args) throws Exception {
EventHandler eventHandler = new EventHandler();
TTListenerA a = new TTListenerA("cllblogs");
TTListenerA b = new TTListenerA("cll");
TTListenerA c = new TTListenerA("Mr丶C");
eventHandler.addEvent(a,"seeNewNews","2018中国进口博览会开幕式");
eventHandler.addEvent(b,"seeNewNews","2018中国进口博览会开幕式");
eventHandler.addEvent(c,"seeNewNews","2018中国进口博览会开幕式");
eventHandler.notifyM();
}
}
控制台打印结果:
尊敬的[cllblogs]用户,您有一条新闻:2018中国进口博览会开幕式
尊敬的[cll]用户,您有一条新闻:2018中国进口博览会开幕式
尊敬的[Mr丶C]用户,您有一条新闻:2018中国进口博览会开幕式