观察者模式
观察者模式主要⽤于处理对象间的⼀对多的关系,是⼀种对象⾏为模式。 该模式的实际应⽤场景⽐较容易确认,当⼀个对象状态发⽣变化时,所有 该对象的关注者均能收到状态变化通知,以进⾏相应的处理。
Subject:
抽象被观察者,仅提供注册和删除观察者对象的接⼝声明。
ConcreteSubject:
具体被观察者对象,该对象中收集了所有需要被通知的 观察者,并可以动态的增删集合中的观察者。当其状态发⽣变化时会通知 所有观察者对象。
Observer:
抽象观察者,为所有观察者定义获得通知的统⼀接⼝;
ConcreteObserver:
观察者对象,其关注对象为
Subject
,能接受
Subject
变化时发出的通知并更新⾃身状态。
1. 观察者模式的应用场景
- 消息队列
- 公众号
- java中的监听器
-
1)spring中ioc的应用 2)事件监听
......
2 观察者模式的优缺点
优点:
1.
被观察者和观察者之间是抽象耦合的;
2.
耦合度较低,两者之间的关联仅仅在于消息的通知;
3.
被观察者⽆需关⼼他的观察者;
4.
⽀持⼴播通信;
缺点:
1.
观察者只知道被观察对象发⽣了变化,但不知变化的过程和缘由;
2.
观察者同时也可能是被观察者,消息传递的链路可能会过⻓,完成所有
通知花费时间较多;
3.
如果观察者和被观察者之间产⽣循环依赖,或者消息传递链路形成闭
环,会导致⽆限循环;
3 你的项⽬是怎么⽤的观察者模式?
在⽀付场景下,⽤户购买⼀件商品,当⽀付成功之后三⽅会回调⾃身,在 这个时候系统可能会有很多需要执⾏的逻辑(如:更新订单状态,发送邮 件通知,赠送礼品…
),这些逻辑之间并没有强耦合,因此天然适合使⽤ 观察者模式去实现这些功能,当有更多的操作时,只需要添加新的观察者 就能实现,完美实现了对修改关闭,对扩展开放的开闭原则。也是应用场景中消息队列的应用,新消息发送给消息队列的主题Topic,新增一个消费对象就新增一个订阅主题的对象。
4. 代码实例
1. 观察者需要实现的接口
/**
* 观察者需要实现的接口
*
* @author WHM
*/
public interface ApplicationContextAware {
// 注入ioc容器
void setApplicationContext(ApplicationContext applicationContext);
}
2 观察者实现类
/**
* 观察者实现类
* @author WHM
*/
public class LoginFilter implements ApplicationContextAware {
@SuppressWarnings("unused")
private ApplicationContext applicationContext;
public LoginFilter(ApplicationContext applicationContext) {
//将当前对象当如ioc
applicationContext.registerObserver(this);
}
public void setApplicationContext(ApplicationContext applicationContext) {
System.out.println("ioc被注入了LoginFilter");
this.applicationContext = applicationContext;
}
}
3 被观察者接口
package pattern.observer;
/**
* 被观察者 需要实现三个接口
*
* @author WHM
*/
public interface ApplicationContext {
/**
* 注册观察者,也就是ioc的容器(bean)
*
* @author WHM
*/
void registerObserver(ApplicationContextAware applicationContextAware);
/**
* 移除观察者
*
* @author WHM
*/
void clearObserver(ApplicationContextAware applicationContextAware);
/**
* 更新观察者的状态
*
* @author WHM
*/
void notifyObserver();
/**
* 创建容器
*
* @author WHM
*/
void onCreate();
public int observerGs();
}
4 被观察者实现类
package pattern.observer;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* 被观察者具体实现类
* @author WHM
*/
public class WebAppLicationContext implements ApplicationContext {
private Map<String,ApplicationContextAware> observers = new HashMap<String,ApplicationContextAware>();
public WebAppLicationContext() {
}
@Override
public void registerObserver(ApplicationContextAware applicationContextAware) {
this.observers.put(applicationContextAware.getClass().getSimpleName(), applicationContextAware);
}
@SuppressWarnings("unlikely-arg-type")
public void clearObserver(ApplicationContextAware applicationContextAware) {
this.observers.remove(applicationContextAware).getClass().getSimpleName();
}
@Override
public void notifyObserver() {
Set<String> observerNames = observers.keySet();
if(observerNames.size() <= 0) {
return;
}
for(String oName : observerNames) {
this.observers.get(oName).setApplicationContext(this);
}
}
@Override
public void onCreate() {
System.out.println("ioc 容器在初始化中");
//通知观察者
this.notifyObserver();
}
public int observerGs() {
return observers.size();
}
}
5 验证类
/**
* 模拟spring中bean获取ioc状态
*
* @author WHM
*/
public class TMain {
@SuppressWarnings("unused")
public static void main(String[] args) {
ApplicationContext context = new WebAppLicationContext();
LoginFilter SimpleUrlHandlerMapping = new LoginFilter(context);
context.onCreate();
System.out.println("容器bean个数:" + context.observerGs());
}
}
6 结果
5 总结:
不管叫什么名字
发布订阅也好,
观察者也好。这个模式的核心就是
当一个对象改变时,同时要去改变多个订阅的对象。
目前很场景的就是公众号,订阅号,我订阅了很多公众号,每天都有精彩的文章可以看到,也能知道技术的更新程度,毕竟有大牛分享。