问题引出
气象站项目
接到一个气象站的合同
可以监测到湿度温度这些变化
做一个开放接口 让第三方接入
现有接口:提供温度,气压和湿度的接口
目标:测量数据更新时需实时通知给第三方
WeatherData类
先写代码不使用观察者模式
package com.weatherstation.mark;
public class WeatherTest {
public static void main(String[] args) {
CurrentWeatherBoard currentWeatherBoard;
WeatherStation weatherStation;
currentWeatherBoard=new CurrentWeatherBoard();
weatherStation=new WeatherStation(currentWeatherBoard);
weatherStation.setData(28,160,30);
}
}
package com.weatherstation.mark;
public class CurrentWeatherBoard {
private float currentTemperature;
private float currentPressure;
private float currentHumidity;
public void update(float currentTemperature,float currentPressure,float currentHumidity){
this.currentTemperature=currentTemperature;
this.currentPressure=currentPressure;
this.currentHumidity=currentHumidity;
display();
}
public void display(){
System.out.println("Now currentTemperature:"+currentTemperature);
System.out.println("Now currentPressure:"+currentPressure);
System.out.println("Now currentHumidity:"+currentHumidity);
}
}
package com.weatherstation.mark;
public class WeatherStation {
private float currentTemperature;
private float currentPressure;
private float currentHumidity;
private CurrentWeatherBoard currentWeather;
public float getCurrentTemperature() {
return currentTemperature;
}
public float getCurrentPressure() {
return currentPressure;
}
public float getCurrentHumidity() {
return currentHumidity;
}
public WeatherStation(CurrentWeatherBoard currentWeather){
this.currentWeather=currentWeather;
}
public void update(float tempTemperature,float tempPressure,float tempHumidity){
this.currentTemperature=currentTemperature;
this.currentPressure=currentPressure;
this.currentHumidity=currentHumidity;
}
//增加公告板 code需要改变
public void dataChange(){
currentWeather.update(getCurrentTemperature(),getCurrentPressure(),getCurrentHumidity());
}
public void setData(float tempTemperature,float tempPressure,float tempHumidity){
this.currentTemperature=tempTemperature;
this.currentPressure=tempPressure;
this.currentHumidity=tempHumidity;
dataChange();
}
}
问题如果新加公告栏 需要改变代码 扩展性不好
怎么解决 思考问题
观察者模式原理
订报业务
1.报社 Subject
2.用户 Observer
2.Subject 注册 移除 通知
3.Observer :接收输入
定义:
对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject通知Observer变化
观察者模式实现
类图
接口定义:
package com.mode.weatherstation.mark;
//气象站 当做订阅的主题接口
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
package com.mode.weatherstation.mark;
public interface Observer {
public void update(float currentTemperature,float currentPressure,float currentHumidity);
}
观察者类:
package com.mode.weatherstation.mark;
public class StaticWeatherBoard implements Observer
{
private float currentTemperature;
private float currentPressure;
private float currentHumidity;
private float aveValue;
public void update(float currentTemperature,float currentPressure,float currentHumidity){
aveValue=(currentTemperature+currentPressure+currentHumidity)/3;
display();
}
public void display(){
System.out.println("Ave Value:"+aveValue);
}
}
package com.mode.weatherstation.mark;
public class CurrentWeatherBoard implements Observer{
private float currentTemperature;
private float currentPressure;
private float currentHumidity;
public void update(float currentTemperature,float currentPressure,float currentHumidity){
this.currentTemperature=currentTemperature;
this.currentPressure=currentPressure;
this.currentHumidity=currentHumidity;
display();
}
public void display(){
System.out.println("Now currentTemperature:"+currentTemperature);
System.out.println("Now currentPressure:"+currentPressure);
System.out.println("Now currentHumidity:"+currentHumidity);
}
}
订阅类(主题类):
package com.mode.weatherstation.mark;
import com.weatherstation.mark.CurrentWeatherBoard;
import java.util.ArrayList;
public class WeatherStation implements Subject{
private float currentTemperature;
private float currentPressure;
private float currentHumidity;
private ArrayList<Observer> observers;
public float getCurrentTemperature() {
return currentTemperature;
}
public float getCurrentPressure() {
return currentPressure;
}
public float getCurrentHumidity() {
return currentHumidity;
}
public WeatherStation(){
observers=new ArrayList<Observer>();
}
public void update(float tempTemperature,float tempPressure,float tempHumidity){
this.currentTemperature=currentTemperature;
this.currentPressure=currentPressure;
this.currentHumidity=currentHumidity;
}
//增加公告板 code需要改变
public void dataChange(){
notifyObservers();
}
public void setData(float tempTemperature,float tempPressure,float tempHumidity){
this.currentTemperature=tempTemperature;
this.currentPressure=tempPressure;
this.currentHumidity=tempHumidity;
dataChange();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
if(observers.contains(o))
{
observers.remove(o);
}
}
@Override
public void notifyObservers() {
for (Observer o:observers){
o.update(getCurrentTemperature(),getCurrentPressure(),getCurrentHumidity());
}
}
}
测试类:
package com.mode.weatherstation.mark;
public class WeatherTest {
public static void main(String[] args) {
CurrentWeatherBoard currentWeatherBoard;
StaticWeatherBoard staticWeatherData;
WeatherStation weatherStation;
weatherStation=new WeatherStation();
currentWeatherBoard=new CurrentWeatherBoard();
staticWeatherData=new StaticWeatherBoard();
weatherStation.registerObserver(currentWeatherBoard);
weatherStation.registerObserver(staticWeatherData);
weatherStation.setData(35,120,38);
System.out.println();
System.out.println();
System.out.println();
weatherStation.removeObserver(staticWeatherData);
weatherStation.setData(25,150,50);
}
}
接口定义 一对多
不用修改代码,重启服务
Java 内置观察者(JDK9 已经弃用)
Observable 订阅者 主题 是一个类
Observer 观察者 是一个接口
package com.javainner.weathersatation.mark;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;
//是一个类 所以不能多重继承
public class WeatherStation extends Observable {
private float currentTemperature;
private float currentPressure;
private float currentHumidity;
private ArrayList<Observer> observers;
public float getCurrentTemperature() {
return currentTemperature;
}
public float getCurrentPressure() {
return currentPressure;
}
public float getCurrentHumidity() {
return currentHumidity;
}
public WeatherStation(){
observers=new ArrayList<Observer>();
}
public void update(float tempTemperature,float tempPressure,float tempHumidity){
this.currentTemperature=currentTemperature;
this.currentPressure=currentPressure;
this.currentHumidity=currentHumidity;
}
//需要注意 java 内置观察者 需要调用setChanged方法
public void dataChange(){
setChanged();
notifyObservers(new Data(getCurrentTemperature(),getCurrentPressure(),getCurrentHumidity()));
}
public void setData(float tempTemperature, float tempPressure, float tempHumidity){
this.currentTemperature=tempTemperature;
this.currentPressure=tempPressure;
this.currentHumidity=tempHumidity;
dataChange();
}
//载体类,放更新数据
public class Data{
private float currentTemperature;
private float currentPressure;
private float currentHumidity;
public Data(float currentTemperature, float currentPressure, float currentHumidity) {
this.currentTemperature = currentTemperature;
this.currentPressure = currentPressure;
this.currentHumidity = currentHumidity;
}
public float getCurrentTemperature() {
return currentTemperature;
}
public float getCurrentPressure() {
return currentPressure;
}
public float getCurrentHumidity() {
return currentHumidity;
}
}
}
package com.javainner.weathersatation.mark;
import java.util.Observable;
import java.util.Observer;
public class CurrentWeatherBoard implements Observer {
private float currentTemperature;
private float currentPressure;
private float currentHumidity;
public void display(){
System.out.println("Now currentTemperature:"+currentTemperature);
System.out.println("Now currentPressure:"+currentPressure);
System.out.println("Now currentHumidity:"+currentHumidity);
}
@Override
public void update(Observable o, Object arg) {
this.currentTemperature=((WeatherStation.Data)arg).getCurrentTemperature();
this.currentPressure=((WeatherStation.Data)arg).getCurrentTemperature();
this.currentHumidity=((WeatherStation.Data)arg).getCurrentPressure();
display();
}
}
package com.javainner.weathersatation.mark;
import java.util.Observable;
import java.util.Observer;
public class StaticWeatherBoard implements Observer
{
private float currentTemperature;
private float currentPressure;
private float currentHumidity;
private float aveValue;
public void display(){
System.out.println("Ave Value:"+aveValue);
}
@Override
public void update(Observable o, Object arg) {
aveValue=aveValue=(((WeatherStation.Data)arg).getCurrentTemperature()+((WeatherStation.Data)arg).getCurrentTemperature()+((WeatherStation.Data)arg).getCurrentPressure())/3;
display();
}
}
package com.javainner.weathersatation.mark;
public class WeatherTest {
public static void main(String[] args) {
CurrentWeatherBoard currentWeatherBoard;
StaticWeatherBoard staticWeatherData;
WeatherStation weatherStation;
weatherStation=new WeatherStation();
currentWeatherBoard=new CurrentWeatherBoard();
staticWeatherData=new StaticWeatherBoard();
//执行顺序 最后注册的先执行代码
weatherStation.addObserver(currentWeatherBoard);
weatherStation.addObserver(staticWeatherData);
weatherStation.setData(35,120,38);
System.out.println();
System.out.println();
System.out.println();
weatherStation.deleteObserver(staticWeatherData);
weatherStation.setData(25,150,50);
}
}
观察者模式关键点
生活上订报 订牛奶
解决问题:类或者对象之间存在一对多的依赖关系
1 subject 主题者 通知 推送信息 拉信息(提取信息)
多 observer 观察者
松耦合 主题者和观察者之间的关系
Java内置观察者 推和拉都实现了
设计原则体现
原则1:
找出程序中会变化的方面,然后将其和固定不变的方面相分离
体现:
在观察者模式中,会改变的是主题的状态。以及观察者的数目和类型。用这个模式,你可以改变依赖该主题状态对象。却不必改变主题。这就叫提前规划
原则2:
针对接口编程,不针对实现编程
体现:
主题与观察者都使用接口:观察者利用主题的接口向主题注册,而主题利用观察者接口通知观察者。这样可以让两者之间运作正常。又同事具有松耦合的优点
原则3:
多用组合,少用继承
体现:
观察者模式利用”组合“将许多观察者组合进主题中。对象之间的这种关系不是通过继承产生的。而是在运行时利用组合的方式而产生的。
注:如果文章有任何错误或不足,请各位大佬尽情指出,评论留言留下您宝贵的建议!如果这篇文章对你有些许帮助,希望可爱亲切的您点个赞推荐一手,非常感谢啦