持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第31天,点击查看活动详情。
在我们生活中存在着许多观察者模式的例子,人与人,物与物之间都是存在着某种依赖的,很难出现两个事物独立变化而不相互依赖的,往往一件事物的改变会出发依赖事物的改变,并且所依赖事物的改变会触发一定的反应,像这种事物之间存在依赖并且会随着一件事物的改变而做出反应的现象我们就可以使用观察者模式体现出来.比如一场考试中如果存在学生作弊那么监考老师会做出相应反应,此刻考生就是被观察的对象而监考老师就是观察者.比如当下汽车市场消费低迷,国家会出台一些补贴政策来刺激消费,此刻消费者就是被观察的对象,国家就是观察者。
观察者模式
观察者模式(Observer Pattern)属于行为模式。当类之间存在一对多关系的时候,当一个对象变化时,其他依赖该对象的对象都会收到通知,并且会随着变化。
该模式角色之间不涉及继承,而是通过组合的方式实现,被观察者在抽父类中将观察者们组合到类的内部,并且在被观察者的具体实现内对观察者们同时进行操作。
涉及角色:
- 观察者
- 被观察的对象
生活中的例子:
订阅博客,当博主更新博客的时候会通知所有订阅者。
实现
我们以订阅博客为例:
定义一个抽象的订阅者:订阅者就是观察者,他会在博主发出博客而做出相应动作:观看博客、评论博客等
public interface IObserver {
/**
* 被通知
*/
void notice();
}
定义具体订阅者:
@Data
public class Observer implements IObserver {
private String name;
private Integer num = 0;
public Observer(String name) {
this.name = name;
}
@Override
public void notice() {
System.out.println(this.getName()+"=>您订阅的文章已更新");
num++;
}
}
定义博客接口和一些对订阅者操作相关方法:
/**
* 添加订阅者
* @param observer
*/
void addObserver(IObserver observer);
/**
* 取消订阅
* @param observer
*/
void delObserver(IObserver observer);
/**
* 通知所有订阅者
*/
void notifyAllObserver();
/**
* 发布博客
*/
void releaseBlog();
}
定义抽象类:
将订阅者组合进来,并实现对订阅者增删操作和通知所有订阅者操作。 此刻博客就是一个被观察的对象,在发出博客的时候会通知所有订阅者。
public abstract class AbstractBlog implements IBlog{
private List<IObserver> list = new ArrayList<>();
@Override
public void addObserver(IObserver observer) {
list.add(observer);
}
@Override
public void delObserver(IObserver observer) {
list.remove(observer);
}
@Override
public void notifyAllObserver() {
list.forEach(IObserver::notice);
}
}
博客实现类:
发布博客时通知所有订阅者:
public class Blog extends AbstractBlog {
@Override
public void releaseBlog() {
System.out.println("博客发布,通知所有订阅者");
super.notifyAllObserver();
}
}
测试:
public class ObserverTest {
public static void main(String[] args) {
Blog blog = new Blog();
blog.addObserver(new Observer("yyc1"));
blog.addObserver(new Observer("yyc2"));
blog.addObserver(new Observer("yyc3"));
//发布博客通知所有订阅者
blog.releaseBlog();
}
}
优缺点
优点
观察者与被观察者的耦合关系建立在抽象层,在抽象层定义了观察者与被观察者的联系,而在具体实现的时候可以不用关心之间的耦合关系
缺点
如果说观察者与被观察者存在循环依赖的情况,很有可能造成程序奔溃。