设计模式之旅(三)--观察者模式

来源:互联网 发布:数据朔源技术的目标 编辑:程序博客网 时间:2024/06/04 19:01

在上一站中,我们了解了木叶村最神秘宇智波一族,接下来这一站,我想我们还是从木叶非常著名的几位实业家开始说起吧...

丁次:对,就是那个胖胖的小伙,他不仅喜欢吃团子,而且他还挺有商业头脑,自己开了一家团子店,可是,自从开业之后,就有一个问题一直在困扰他,就是他做的团子时好时坏,后来,他终于发现了其中的奥秘,是自己对木叶的气温没有把握好-_- 天气多变,温度多变,而自己的的制作工艺没有变化,自然团子的口味不一样,所以说,丁次有一个迫切的需求就是要随时了解木叶的温度变化。

自来也:好色仙人,最近发展了一批小伙伴,培育了一众小青蛙,不过,由于不了解空气湿度的变化,不能及时为小伙伴提供良好的服务,所以自来也老师最近有一个愿望,想要及时的了解木叶的湿度变化。

志乃:子承父业,志乃继承了父亲的衣钵,将家族的虫子养殖事业发展的越来越大,他需要更多的了解木叶的天气变化,他要随时的了解木叶的温度 气压 湿度

就这样,在同一天,这三人同时来到了木叶气象局,要求气象局能够在自己的家里安装一块气象公告板,好及时的显示自己所需要的气象数据。值班的是鸣人-_-,鸣人是个热心人,当场就答应了三位,”OK,我立马给大家拿出设计方案“

鸣人还是很靠谱的,拿出了设计图,就给三个人分析了目前的情况:


看,关于气象信息的收集这都是我们气象局的事情,我们给你们设计好一个WeatherData类,当一旦有气象更新时,立马将您所需的气象信息给呈现出来,然后刷刷刷的在机器上码出了以下例子:

public class WeaterData {//...部分代码public void weatherChange(){float temp = getTemperature();float humidity = getHumidity();float pressure = getPressure();board_One.update(temp, humidity, pressure);board_Two.update(temp, humidity, pressure);board_Three.update(temp, humidity, pressure);}}

三位客户正在研究着鸣人的设计方案,鸣人有点小得意,这时,在一旁的雏田,好像有话要说,不断的拉鸣人的衣角。。。

雏田将鸣人拉出去,说:

这个设计,都是针对具体实现进行的编程,这样以后如果鹿丸、卡卡西老师....他们如果也需要气象信息时,我们那必须要修改程序的代码了,这样对代码的维护性及可扩展性都是很大的挑战啊;而且,你再看,后面我们传递的参数都是一样的,这是这个项目中共有的部分,这种统一的地方,我们是不是应该考虑进行封装起来啊

鸣人大惊失色,才发现自己刚才实在太大意了,问雏田有什么好的解决办法,雏田也是不知道改怎么办。。。

这时,雏田,发现了桌子上的报纸,突然想到了一件事情,说,我们可以向佐助的报社学习啊!

”怎么说?“

雏田继续说,我们大家都是向佐助的报社订阅报纸,就像下面这样:


大家想订就订,想退订就退订,这样大家都很方便的。佐助不需要为每一个订购者提供单独的服务,所有的订购者均被一视同仁。订购者,也是如果不想订阅,可以随时取消订阅。


哈哈,鸣人大笑,原来佐助也挺聪明的嘛,这不就是卡卡西老师教的招数嘛,就是使用了:

观察者模式:定义了对象之间的一对多依赖关系,这样一来,当对象的状态改变时,他的所有依赖这都会收到通知并完成自动更新

鸣人仔细想过之后对雏田说,我有办法了,看我设计一个超棒的系统的,先给你看看什么是观察者模式:


在这个模式中,关键是定义两个接口,subject、observer接口,subject接口主要用于定义注册、删除、通知这三个方法,observer接口则主要是定义update方法,提供观察者统一的方法接口,当然观察者可能还有一些可选的公共方法,可以另外写一个接口进行定义。当然,针对接口编程可以实现较好的解耦,如果对此不是很理解,那就接下来继续听鸣人说吧。

以我们的气象站为例,我们首先定义subject及observer接口:

public interface Subject {      public void registerObserver(Observer o);      public void removeObserver(Observer o);      public void notifyObserver();  }  
public interface Observer {      public void update(float temp, float humidity, float pressure);  } 
然后就要考虑实现具体的接口了,先看实现subject接口

import java.util.ArrayList;    public class WeatherData implements Subject {        private ArrayList observers;      private float temp;      private float humidity;      private float pressure;            public WeatherData(){          observers = new ArrayList();      }            public void setMeasurements(float temp, float humidity, float pressure){          this.temp = temp;          this.humidity = humidity;          this.pressure = pressure;          measurementsChange();      }            public void measurementsChange(){          notifyObserver();      }            @Override      public void registerObserver(Observer o) {          // TODO Auto-generated method stub          observers.add(o);      }        @Override      public void removeObserver(Observer o) {          // TODO Auto-generated method stub          int i = observers.indexOf(o);          if(i>=0){              observers.remove(i);          }      }        @Override      public void notifyObserver() {          // TODO Auto-generated method stub          for(int i=0;i<observers.size();i++){              Observer observer = (Observer) observers.get(i);              observer.update(temp, humidity, pressure);          }      }    }  
在这个类中保存了一个观察者的ArrayList,所有的观察者的应用都保存在其中。可以进行注册、删除、通知观察者(具体的代码实现,自行体会~~)

在所有的观察者中,我们又发现有其他的公共方法 display(),所以定义此接口:

public interface DisplayElement {      public void display();  }  
那么接下来,看看观察者的实现吧

public class CurrentConditionDisplay implements Observer, DisplayElement {        private float temp;      private float humidity;      private float pressure;      private Subject weatherData;      public CurrentConditionDisplay(Subject weatherData){  //      保存引用是为了以后更方便的取消注册          this.weatherData = weatherData;          weatherData.registerObserver(this);      }            @Override      public void display() {          // TODO Auto-generated method stub          System.out.println("AAA current tempreature is: "+temp+" , humidity is: "+humidity+" , pressure is: "+pressure);      }        @Override      public void update(float temp, float humidity, float pressure) {          // TODO Auto-generated method stub          this.temp = temp;          this.humidity = humidity;          this.pressure = pressure;          display();      }        public Subject getWeatherData() {          return weatherData;      }        public void setWeatherData(Subject weatherData) {          this.weatherData = weatherData;      }  
另外两个具体的观察者,啊,不对,太投入了,忘记了这是鸣人在设计天气显示板,另外两个具体的天气显示板,大家可以自行添加哈,当然,依据个人喜好,酌情添加都没问题

好了,最后咱们写一个测试类试一下(如果有类在上面的代码中未实现,请自行补全,当然,在文章底部,提供完整代码下载)

public class Main {      public static void main(String[] args) {            WeatherData weatherData = new WeatherData();          CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay(weatherData);          CurrentPressure currentPressure = new CurrentPressure(weatherData);          CurrentTemp currentTemp = new CurrentTemp(weatherData);          CurrentPressure currentPressure2 = new CurrentPressure(weatherData);                  //在布告板中保存注册主题的引用,可以方便的进行取消注册          currentTemp.getWeatherData().removeObserver(currentTemp);          weatherData.removeObserver(currentPressure2);          weatherData.setMeasurements(80, 30, 30.4f);      }    

扯远了,继续说木叶那三位哈,他们看过鸣人的设计之后拍手大赞,自来也老师手舞足蹈的说道,”鸣人你很棒啊,遵循了针对接口编程的原则,为交互对象之间的松耦合设计做了很多努力,即使有新的观察者出现,我们也可以方便的添加,并且我们可以独立的复用主题和观察者,因为二者并非紧密耦合的“

这时,鸣人竟然语重心长的说,老师啊,给你出个问题,你现在是观察者的身份,有没有想过你也可以成为主题呢,在接受我的天气信息之后,既用于个人使用,也销售给你的订阅者们^_^

好吧,自来也老师有点手足无措了(好吧,大家可以想一下下)


说好的源码在这里,请戳HERE,源码下载


0 0
原创粉丝点击