观察者模式:
原理:对象之间多对一依赖的一种设计方案,被依赖的对象是Subject,依赖的对象称为Observer,Subject通知Observer变化
比如:定牛奶业务
有一家定制送牛奶业务的公司,当我们需要定制牛奶的时候,我们只需要找到这家公司,然后和它注册定制牛奶,那么这家公司每天早上都会给你送牛奶,当你不需要的时候,我们可以在去这家公司取消这个业务,然后这公司就不会给你送牛奶了
在这个案例中我们的Subject是公司,Observer是定制牛奶的用户
从这里我们可以看出
奶站----------Subject
用户----------Observer
Subject 登记记录,移除和通知
Observer 接收输入
然后在根据将变化的抽象成接口+实现
Interface Subject |
registerObserver() removeObserver() notifyObserver() |
Interface Observer |
update() |
代码示例:
这里我们在这个场景下使用观察者模式:有一个气象台(Subject)提供温度、湿度、气压给发布当天天气的公司(Observer),每当气象台的数据有变化的时候都要实时的提供给这家公司更新数据
新的需求又有新的公司(Observer)需要这些数据去实现天气的预报功能,我们只需要将这个公司注册就好了
1.创建Subject接口 提供注册、移除、通知三个抽象方法
public interface Subject {
public void registerObserver(Observer o);
public void removeObsever(Observer o);
public void notifyObserver();
}
2.创建Observer接口 更新最新的消息
public interface Observer {
public void update(float mTemperature,float mPressure,float mHumidity);
}
3.实现Subject接口 通知有两种方式 第一种就是直接把数据传递给Observer 第二种就是我们通知Observer有消息(推送),Observer自己通过方法获取数据(拉的方式)
public class WeatherDate implements Subject{
private float mTemperature;
private float mPressure;
private float mHumidity;
//这个用来存放注册的观察者
private ArrayList<Observer> mObservers;
public WeatherDate() {
// TODO Auto-generated constructor stub
mObservers = new ArrayList<Observer>();
}
public float getmHumidity() {
return mHumidity;
}
public float getmPressure() {
return mPressure;
}
public float getmTemperature() {
return mTemperature;
}
public void dataChange(){
notifyObserver();
}
//这个方法模拟数据的改变
public void setDate(float mTemperature, float mPressure, float mHumidity){
this.mHumidity = mHumidity;
this.mPressure = mPressure;
this.mTemperature = mTemperature;
dataChange();
}
@Override
public void registerObserver(Observer o) {
// TODO Auto-generated method stub
mObservers.add(o);
}
@Override
public void removeObsever(Observer o) {
// TODO Auto-generated method stub
if(mObservers.contains(o))
mObservers.remove(o);
}
@Override
public void notifyObserver() {
// TODO Auto-generated method stub通知每一个观察者
for(int i=0,len=mObservers.size();i<len;i++){
//这里有一个问题就是当我们需要传递的数据非常多的时候,这样来传递是不行的
mObservers.get(i).update(getmHumidity(), getmPressure(), getmTemperature());
}
}
}
4.观察者 当前天气显示的观察者
public class CurrentConditions implements Observer{
private float mTemperature;
private float mPressure;
private float mHumidity;
@Override
public void update(float mTemperature, float mPressure, float mHumidity) {
this.mTemperature = mTemperature;
this.mPressure = mPressure;
this.mHumidity = mHumidity;
//一有数据的更新那么就调用它的显示的方法更新最新的数据
display();
}
public void display(){
System.out.println("今天的mTemperature:"+mTemperature);
System.out.println("今天的mPressure:"+mPressure);
System.out.println("今天的mHumidity:"+mHumidity);
}
}
5.当有新的需求加入新的观察者 预报明天天气的观察者
public class ForecastConditions implements Observer{
private float mTemperature;
private float mPressure;
private float mHumidity;
@Override
public void update(float mTemperature, float mPressure, float mHumidity) {
// TODO Auto-generated method stub
this.mTemperature = mTemperature;
this.mPressure = mPressure;
this.mHumidity = mHumidity;
//一旦数据 有新的更新那么就调用它的显示功能
display();
}
public void display(){
System.out.println("明天的天气是mTemperature:"+mTemperature+Math.random());
System.out.println("明天的天气是mPressure:"+mPressure+Math.random());
System.out.println("明天的天气是mHumidity:"+mHumidity+Math.random());
}
}
6.在主类中注册、移除观察者并模拟数据的改变通知观察者
public class ForecastConditions implements Observer{
private float mTemperature;
private float mPressure;
private float mHumidity;
@Override
public void update(float mTemperature, float mPressure, float mHumidity) {
// TODO Auto-generated method stub
this.mTemperature = mTemperature;
this.mPressure = mPressure;
this.mHumidity = mHumidity;
//一旦数据 有新的更新那么就调用它的显示功能
display();
}
public void display(){
System.out.println("明天的天气是mTemperature:"+mTemperature+Math.random());
System.out.println("明天的天气是mPressure:"+mPressure+Math.random());
System.out.println("明天的天气是mHumidity:"+mHumidity+Math.random());
}
}
7.输出的结果
今天的mTemperature:50.0
今天的mPressure:40.0
今天的mHumidity:30.0
明天的天气是mTemperature:50.00.8126107027953531
明天的天气是mPressure:40.00.5972877730492465
明天的天气是mHumidity:30.00.7082692517755711
明天的天气是mTemperature:80.00.2161028662759591
明天的天气是mPressure:70.00.7948252265828729
明天的天气是mHumidity:60.00.3809028969571353
java内置观察者
Observer 是通过继承Observable类 已经实现了注册、移除、通知,直接使用就好不用再实现了 通知观察者要setChanged();
Observer 通过实现Observer接口
1.设计Observer
public class WeatherDate extends Observable {
private float mTemperature;
private float mPressure;
private float mHumidity;
public float getmHumidity() {
return mHumidity;
}
public float getmPressure() {
return mPressure;
}
public float getmTemperature() {
return mTemperature;
}
public void dataChange(){
//必须写setChanged 设置变化,设置了一个boolean变量表示数据是有更新的 在这一步
//会判断Boolean是否为真,真的就通知
this.setChanged();
this.notifyObservers(new Data(getmTemperature(), getmPressure(), getmHumidity()));
}
//这个方法模拟数据的改变
public void setDate(float mTemperature, float mPressure, float mHumidity){
this.mHumidity = mHumidity;
this.mPressure = mPressure;
this.mTemperature = mTemperature;
dataChange();
}
//把传递的数据放在这里
public class Data{
public float mTemperature;
public float mPressure;
public float mHumidity;
public Data(float mTemperature, float mPressure, float mHumidity) {
// TODO Auto-generated constructor stub
this.mHumidity = mHumidity;
this.mPressure = mPressure;
this.mTemperature = mTemperature;
}
}
}
2.设计观察者 当天的天气显示
public class CurrentConditions implements Observer{
private float mTemperature;
private float mPressure;
private float mHumidity;
@Override
public void update(Observable o, Object arg) {
// TODO Auto-generated method stub
this.mTemperature = ((Data)(arg)).mTemperature;
this.mPressure = ((Data)(arg)).mPressure;
this.mHumidity = ((Data)(arg)).mHumidity;
display();
}
public void display(){
System.out.println("今天的mTemperature:"+mTemperature);
System.out.println("今天的mPressure:"+mPressure);
System.out.println("今天的mHumidity:"+mHumidity);
}
}
3.新的需求需要添加新的观察者 预报天气
public class ForecastConditions implements Observer {
private float mTemperature;
private float mPressure;
private float mHumidity;
@Override
public void update(Observable o, Object arg) {
// TODO Auto-generated method stub
this.mTemperature = ((Data)(arg)).mTemperature;
this.mPressure = ((Data)(arg)).mPressure;
this.mHumidity = ((Data)(arg)).mHumidity;
display();
}
public void display(){
System.out.println("明天的mTemperature:"+(mTemperature+1));
System.out.println("明天的mPressure:"+(mPressure+1));
System.out.println("明天的mHumidity:"+(mHumidity+1));
}
}
4.主函数中注册、移除、模拟通知
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
WeatherDate weatherDate = new WeatherDate();
CurrentConditions conditions = new CurrentConditions();
ForecastConditions forecastConditions = new ForecastConditions();
//添加注册者
weatherDate.addObserver(conditions);
weatherDate.addObserver(forecastConditions);
//后注册的先接到通知
weatherDate.setDate(30, 40, 50);
//移除观察者
weatherDate.deleteObserver(conditions);
weatherDate.setDate(50, 60, 70);
}
}
总结:
1.观察者模式是解决对象之间有一对多关系项目的极好解决模式,具有非常好的扩展性、可维护性、灵活性,做到很好的高内聚松耦合