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

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

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

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

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

就这样,在同一天,这三人同时来到了木叶气象局,要求气象局能够在自己的家里安装一块气象公告板,好及时的显示自己所需要的气象数据。值班的是鸣人-_-,鸣人是个热心人,当场就答应了三位,”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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值