在许多场景,是需要建立一对多,消息及时且弱耦合,设计模式面向接口,推出观察者模式。
场景:气象数据发送给三个信息版,分别为当前数据,气象统计值,天气预报,一旦气象数据更新,三个信息版就要封信面板信息展示。
请查看为不使用观察者模式的代码:
/** * 利用weather 数据更新3个信息版,当前数据,气象统计值,天气预报 */ public class weather { private float temperature;//温度 private float humidity;//湿度 private float pressure;//气压 public float getTemperature() { return temperature; } public weather(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; } public void setTemperature(float temperature) { this.temperature = temperature; } public float getHumidity() { return humidity; } public void setHumidity(float humidity) { this.humidity = humidity; } public float getPressure() { return pressure; } public void setPressure(float pressure) { this.pressure = pressure; } public void paramChanged(){ float temp = getTemperature(); float hum = getHumidity(); float pressure = getPressure(); currentCondutionDisplay.update(temp,hum,pressure); //如果要添加删除信息板就要在weather类删除添加,造成强耦合 } }
class currentCondutionDisplay { private float temperature;//温度 private float humidity;//湿度 private float pressure;//气压 public currentCondutionDisplay(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; } protected static void update(float temperature, float humidity, float pressure){ display(temperature,humidity,pressure); } private static void display(float temperature, float humidity, float pressure){ System.out.println("当前天气 温度 "+temperature + "湿度"+humidity+"气压 "+pressure); } }
public class testmain { public static void main(String[] args) { weather weatherdata = new weather(38,60,1000); weatherdata.paramChanged(); } }
弊端:假设需要添加删除信息版,就需要在weather类修改,造成类之间的强耦合。
对此,引入设计模式中的观察者模式
观察者模式含义:当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
观察者模式目的:解决强耦合问题。
干说定义枯燥,举个场景:邮局发送示例
小明(即你自己)向邮局发送信件,邮局我们可以当成主体(subject)被观察者,小明想要通过邮局发送信件给三个人,分别为女朋友小红,小明父母,小明朋友小张,这三个人我们可以定义为观察者(observer),我们将三位收信人,写成一个收信列表,即观察者列表,注册给邮局。邮局一旦接受到小明信件,就会更新自己的状态,通知三位收信人,即观察者们,而收信人们(观察者们)收到信件会更新自己的状态,有不同的动作,小红会寄一份带有一片玫瑰花瓣的信件给小明,小明父母会寄土特产给小明,小张则在收到信件直接打电话给小明。但也有突发状况,比如小红生气,拒收小明信件,那么邮局就暂时把收信人列表移除小红,再比如小明想给小红好朋友小紫写信让她跟小红说说好话,那么就加小紫到收信人列表。
观察者模式类似于这样,只不过收信人定义为观察者,实现观察者接口,邮局则定义为被观察者,实现主体接口,邮局和观察者们形成一对多的关系,邮局可以删除添加观察者,推送更新状态给观察者。
在气象局此例中,气象数据weather类为主体,实现subject接口,具有移除添加信息版和改变参数通知信息版,三个信息版为观察者,气象数据更新则update自己的状态,观察者和主体有一个注册的关系建立连接,具体实现可以观察下面流程图
如图,三个面板除了实现obsever接口还实现display接口,具有接口的update()和display()方法,只不过三个信息版可以重写这两个方法。
代码实现:
public interface DisplayElement { public void display(); } public interface Observer { public void update(float temp,float humidity,float pressure); } public interface Subject { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers(); }
public class currentConditionsDisplay implements Observer, DisplayElement { //实现了observer接口,可从weather获得改变 private float temperature; private float humidity; private Subject weather; public currentConditionsDisplay(Subject weather) {//注册,联系subject this.weather = weather; weather.registerObserver(this); } @Override public void display() { System.out.println("Current conditions: "+ temperature +" degrees and "+ humidity+ " %humidity"); } @Override public void update(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity;//将温度湿度保存起来,调用display display(); } }
public class forecastDisplay implements Observer, DisplayElement { //实现了observer接口,可从weather获得改变 private float temperature; private float humidity; private Subject weatherData; private String status; public forecastDisplay(Subject weatherData) {//注册,联系subject this.weatherData = weatherData; weatherData.registerObserver(this); } @Override public void display() { if (this.temperature>37){ this.status = "too hot"; } if(this.temperature<38 & this.temperature>20 & this.humidity>45){ this.status = "warm"; }if(this.temperature<=10){ this.status = "too cold"; } System.out.println("today weather: "+ this.status); } @Override public void update(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity;//将温度湿度保存起来,调用display display(); } }
测试代码:
public class weatherStation { public static void main(String[] args) { weather weather = new weather(); currentConditionsDisplay currentConditionsDisplay = new currentConditionsDisplay(weather); forecastDisplay forecast = new forecastDisplay(weather); weather.setParams(10,20,1000); weather.setParams(25,60,1000); weather.setParams(39,60,1000); } }
实现效果:
观察者模式优缺点:
优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
代码:https://github.com/akadiaego/designPatterns