大家好,我是一位在java学习圈中不愿意透露姓名并苟且偷生的小学员,如果文章有错误之处,还望海涵,欢迎多多指正
如果你从本文 get 到有用的干货知识,请帮忙点个赞呗,据说点赞的都拿到了offer
前言
在开始前,说明一下之前的观察者模式已经修改为现在的,因为之前写的观察者模式存在许多不严谨的地方,并且很多介绍都是一笔带过,没有细说,这版的观察者模式我会用心好好写的
观察者模式
简介:
观察者模式用于解决一个对象和一堆对象之间的关系;另外我们常用的监听器的实现原理就用到了观察者模式,监听的对象一旦发生什么异动,监听者们就会做些事情
引申案例
天气预报知道吧,首先假设有一颗专门用于检测天气情况的卫星,然后有三个气象基站,两个气象台,卫星当然负责检测天气变化然后传递天气信息给所属基站,然后基站传给所属气象台
案例分析
通过案例不难发现,案例中有三类对象,卫星,基站,气象台。关系是基站监控卫星的行为,一旦卫星检测到天气信息就将信息传递给基站,基站就自动接收天气信息,而气象台监控基站的行为,一旦基站传递信息给气象台,那么气象台就接收天气信息
案例代码
卫星规则
为什么写这个规则是因为卫星可能有多个,只要是卫星就有卫星的名字,卫星能传递天气信息(具体怎么传递不同的卫星可能不一样,自己重写实现),也能添加观察者,删除观察者,让观察者做事,如下:
package observer;
import java.util.ArrayList;
@SuppressWarnings("all")
public abstract class Subject {
protected String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//目标对象
//1.先有一个集合 为了存放好多观察者
private ArrayList<Observer> list = new ArrayList<>();
//2.设计添加观察者的方法
public void addObserver(Observer o){
this.list.add(o);
}
//设计删除观察者的方法
public void remove(Observer o){
this.list.remove(o);
}
//设计一个方法 用来检测气象情况
public abstract String checkMeteorology();
//设计一个方法 用来发送天气信息
public abstract void sendMessage();
//4.通知所有的观察者 让观察者去做自己的事情
public void notifyObservers(String message){
for(Observer o : list){
o.receiveMessage(message);
}
}
}
风云一号卫星
package observer;
import java.util.Random;
@SuppressWarnings("all")
public class Satellite extends Subject{
public Satellite(String name){
this.name = name;
}
private String heavyRain = "暴雨"; //1
private String moderateRain = "中雨"; //2
private String lightRain = "小雨"; //3
private String sunShine = "天晴"; //4
private String overcast = "天阴"; //5
private String cloudy = "多云"; //6
//设计一个方法 用来检测气象情况 随机天气纯属做着好玩(毕竟没法真的去检测天气)
public String checkMeteorology(){
Random random = new Random();
int weatherNumber = random.nextInt(6) + 1; //1~6
String weather = heavyRain;
switch(weatherNumber){
case 1:
break;
case 2:
weather = moderateRain;
break;
case 3:
weather = lightRain;
break;
case 4:
weather = sunShine;
break;
case 5:
weather = overcast;
break;
case 6:
weather = cloudy;
break;
}
return weather;
}
//设计一个方法 用来发送天气信息
public void sendMessage(){
//先检测获取天气信息
String weather = this.checkMeteorology();
System.out.println(this.name + "卫星检测到" + weather + "的信息并传出");
//卫星发信息的同时告知所有基站(观察者)
this.notifyObservers(weather);
}
}
基站观察者规则
你说你是一个卫星的观察者你就是嘛?继承观察者规则
基站作为卫星的观察者,有自己的名字,存储着观察自己的气象台,也能让气象台自动做事接收天气信息
package observer;
import java.util.ArrayList;
public abstract class Observer {
protected String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
ArrayList<WeatherStation> list = new ArrayList<>();
//设计一个方法 添加气象台对象
public void addWeatherStation(WeatherStation ws){
this.list.add(ws);
}
//观察者做自己的事情
public abstract void receiveMessage(String message);
//4.通知所有的观察者 让观察者去做自己的事情
public void notifyObservers(String message){
for(WeatherStation ws : list){
ws.receive(message);
}
}
}
江西总基站
package observer;
public class BaseStationOne extends Observer {
public BaseStationOne(String name) {
this.name = name;
}
@Override
public void receiveMessage(String message) {
System.out.println(this.name + "接收到" + message + "的信息");
this.send(message);
}
public void send(String message){
for(int i = 0; i < this.list.size(); i++) {
WeatherStation ws = this.list.get(i);
System.out.println(this.name + "收到" + message + "的信息并传给所属的" + ws.getName());
}
this.notifyObservers(message);
}
河南总基站
由于本案例只给江西总基站设置了两个气象台观察者,其他两个基站没有观察者观察他们,所以没有写send方法,相信小伙伴们能理解
package observer;
public class BaseStationTwo extends Observer{
public BaseStationTwo(String name) {
this.name = name;
}
@Override
public void receiveMessage(String message) {
System.out.println(this.name + "接收到" + message + "的信息");
}
}
福建总基站
实际上三个基站写一个类就好了,new三个对象就可以了,但是为了体现当观察者类型不同时的场景,此处分了三个类写,气象台也是
package observer;
public class BaseStationThree extends Observer{
public BaseStationThree(String name) {
this.name = name;
}
@Override
public void receiveMessage(String message) {
System.out.println(this.name + "接收到" + message + "的信息");
}
}
气象台规则
气象台有自己的名字,能接收基站传来的天气信息
package observer;
public abstract class WeatherStation {
protected String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
abstract void receive(String message);
}
宜春气象台
package observer;
//气象台
public class WeatherStationOne extends WeatherStation{
public WeatherStationOne(String name) {
this.name = name;
}
@Override
public void receive(String message) {
System.out.println(this.name + "接收到" + message + "的信息");
}
}
南昌气象台
package observer;
public class WeatherStationTwo extends WeatherStation{
public WeatherStationTwo(String name) {
this.name = name;
}
@Override
public void receive(String message) {
System.out.println(this.name + "接收到" + message + "的信息");
}
}
主方法演示观察者模式
实际上本案例是从无观察者模式演变出使用观察者模式来解决的
风云一号卫星有三个基站观察者
江西总基站有两个气象台观察者
package observer;
public class TestObserver {
public static void main(String[] args){
//天气预报
//气象卫星---->观测天气 暴雨
//基站------->接收消息
//类的关系? is-a has-a use-a
//基站不止一个 每一个基站对象不同
//每多一个基站 需要多一次基站调用方法的过程
//调用的过程很多很麻烦
//Observer
//解决一个对象和一堆对象之间的关系
//一个对象做一件事情 一堆对象跟着自动的做自己的事情
//目标对象---------卫星
//观察者(监听者)----基站
//观察者时刻监测这个目标 聚合
//类的关系从依赖关系---->聚合关系
// Satellite s = new Satellite("风云一号");
// BaseStation bs = new BaseStation();
// bs.receiveMessage(s);
Subject s = new Satellite("风云一号");
BaseStationOne one = new BaseStationOne("江西总基站");
BaseStationTwo two = new BaseStationTwo("河南总基站");
BaseStationThree three = new BaseStationThree("福建总基站");
WeatherStationOne wso = new WeatherStationOne("宜春气象台");
WeatherStationTwo wst = new WeatherStationTwo("南昌气象台");
//添加观察者
s.addObserver(one);
s.addObserver(two);
s.addObserver(three);
one.addWeatherStation(wso);
one.addWeatherStation(wst);
//卫星检测天气信息并传递给所属的基站观察者
s.sendMessage();
}
}
运行结果
不难发现,主方法中只有风云一号卫星做了一件检测天气的事情,但是其他对象都执行了相应的方法,这就是观察者模式的效果(本质:观察者观察到他感兴趣或者说是想要观察的异动后(被观察者的异动),自动做一些已经预先指定的的事情,而不需要手动调用)
总结:
实现手段:
通过一个has a的关系实现,在被观察者的对象中添加一个存放观察者的属性,观察者可以是一个(用一个观察者的类型当属性的类型即可);可以是多个(也可以是不同类型的),此时属性用list集合来存储观察者们,而要实现多种不同的类型的观察者,那么观察者就需要实现一个统一的接口规则或继承一个抽象类的规则,从而通过多态实现不同类型观察者的存储(甚至于不同类型的观察者分开存储,因为不同的观察者可能在观察到变动后的行为并不一致,这个需要好好理解了)。在观察者存储在被观察者的属性中后就能实现监控被观察者的一举一动,因为是你的一部分当然能知晓你做了什么。
应用场景:
一个对象(被观察者)做事情,一堆对象(观察者)跟着做事情
看完了是不是对观察者有了更深刻的理解呢?希望这篇文章能帮到小伙伴们更好的理解观察者模式
之后开始慢慢的更新每一种设计模式,通过生动形象的生活现象举例带你感受设计模式的世界,其实设计模式不难,只是当我们面对某个场景时想不到用哪个设计模式该不该用设计模式,怎么用的更合理…
博客内容来自腾讯课堂渡一教育拓哥,以及自己的一些理解认识,同时看了其他大牛写的设计模式技术文章综合总结出来的