资讯专栏INFORMATION COLUMN

开发之路(设计模式二:观察者模式)

n7then / 306人阅读

摘要:继续我们的设计模式学习,有个好的观察者可以让你开发效率大大提高直接进入正题,我们用一个气象站程序来模拟此模式。内置了观察者模式的实现。

继续我们的设计模式学习,有个好的“观察者”可以让你开发效率大大提高

直接进入正题,我们用一个气象站程序来模拟此模式。
有一个气象站程序,能对湿度,温度,气压进行监测并显示在“显示”装置上面
模拟图如下,此系统中有三个部分
气象站:获取实际气象数据的装置
WeatherData对象:用来追踪气象站发出的数据,并实时更新到布告栏中
布告栏:显示目前天气状况给用户看的

换个比方来说说什么是观察者模式~~~~
1:报社的业务就是出版报纸。
2:向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来,只要你是他们的客户,你就会一直收到新报纸。
3:当你不想再看报纸的时候,取消订阅,报社就不会给你送新报纸了。
4:只要报社一直存在,那么就一直会有人来订阅或取消订阅报纸的服务。
懂了吗?出版社+订阅者=观察者模式,只不过用在“观察者”中,出版社成为“主题”(Subject),订阅者成为“观察者”(Observer)

OK,让我用视图更好的说明

鸭子要加入了

目前只要主题那边更新数据,在观察者这边就都能获得数据了。

此时狗对象不想当观察者了,它向“主题”提出了“离开”的意愿

狗对象离开了,当动物(主题)对象更新数据时,狗对象是不会更新的,它已经不是观察者了,但同时它也可以回来重新“注册”成观察者。

自此观察者模式的核心流程就是这样了,代码先不急着写,先思考下。
观察者模式定义:定义了对象之间一对多依赖,这么一来,当一个对象改变状态时,它的所有依赖着都会收到自动更新。

这样的设计使得主题和多个观察者之间的依赖性降低了,Subject只管“交互”Observer,至于具体怎么实现内容或其他细节内容,Subject不需要知道,它只知道指向Observer就可以了。任何时候我们都可以增加新的观察者,因为主题唯一依赖的东西是一个实现Observer接口的实现类,即使我们随意增加删除观察者都不会影响主题,我们可以独立地复用主题或观察者,如果我们在其他地方需要使用主题或观察者,可以轻易复用,因为二者并非紧耦合。

设计原则一:所做的一切都是为了对象之间能松耦合。(降低依赖度)
注:松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的相互依赖降到最低。

主题接口

package Interface;

/**
 * 设计模式:观察者模式 主题和观察者之间有一对多关系
 * 
 * @author Joy
 * 
 */
// 主题接口
public interface Subject {
    // 这两个方法都需要一个观察者作为变量(参数设为观察者),该观察者是用来注册和删除的
    public void registerObserver(Observer o);

    public void removeObserver(Observer o);

    // 当主题状态改变时调用这个方法,作用是通知观察者
    public void notifyObserver();

}

观察者接口

package Interface;

//观察者接口
public interface Observer {
    //当气象观测数据改变时,主题会把新的状态数据已参数形式传递给观察者
    public void update(float temp, float humidity, float pressure);
}

显示接口(显示数据)

package Interface;
public interface DisplayElement {
    public void display();
}

气象站类(主题实现类)

package Implements;

import java.util.ArrayList;

import Interface.Observer;
import Interface.Subject;

//气象站实现主题接口
//一个气象站(主题)可以更新多个显示(观察者)面板值
public class WeatherData implements Subject {
    // 便于记录观察者
    private ArrayList observers;
    private float temperature;//温度
    private float humidity;//湿度
    private float pressure;//气压

    public WeatherData() {
        observers = new ArrayList();
    }

    // 当注册观察者时,我们只需要把它加入到ArrayList后面即可
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
        
    }
    

    // 当观察者想取消注册时,从list中移除即可
    @Override
    public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        if (i > 0) {
            observers.remove(i);
        }
    }

    @Override
    public void notifyObserver() {
        for (int i = 0; i < observers.size(); i++) {
            //建立观察者对象
            Interface.Observer observer = (Interface.Observer) observers.get(i);
            //将数据更新至观察者对象内
            observer.update(temperature, humidity, pressure);    
            System.out.println("主题更新了数据,观察者那同步更新");
        }
    }

    // 当从气象站得到更新观测值时,我们通知观察者
    public void measurementsChanged() {
        notifyObserver();
    }

    //设置温度,湿度,压力值
    public void setMeasurements(float temperature, float humidity,
            float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }



    
}

下面是两个观察者实现类,气温湿度显示装置和天气预报装置

package Implements;

import Interface.DisplayElement;
import Interface.Observer;
import Interface.Subject;
//观察者实现类
//气温,湿度显示装置
public class CurrentConditionDisplay implements Observer,DisplayElement {
    private float temperature;
    private float humidity;
    private Subject weatherData;
    
    //构造器需要weatherData对象,用于注册
    public CurrentConditionDisplay(Subject weatherData){
        this.weatherData=weatherData;
        //注册
        weatherData.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println("温度板");
        System.out.println("温度:"+temperature+"	"+"湿度:"+humidity);        
    }

    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature=temperature;
        this.humidity=humidity;
        //当update调用时,将温度湿度数据保存起来然后调用display
        display();        
    }
}

天气预报类

package Implements;

import Interface.DisplayElement;
import Interface.Observer;

/**
 * 天气预报装置
 * 
 * @author Joy
 * 
 */
public class ForecastDisplay implements Observer, DisplayElement {
    private float currentPressure = 29.92f; // 当前压力值(赋个初始值)
    private float lastPressure;// 上一次压力值
    private WeatherData weatherData;

    public ForecastDisplay(WeatherData weatherData) {
        this.weatherData = weatherData;
        // 注册成观察者
        weatherData.registerObserver(this);
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        lastPressure = currentPressure;
        //pressure传过来的压力值
        currentPressure = pressure;
        display();
    }

    @Override
    public void display() {
        System.out.print("天气预报: ");
        if (currentPressure > lastPressure) {
            System.out.println("天气晴朗");
        } else if (currentPressure == lastPressure) {
            System.out.println("这次天气状况与上一次相同");
        } else if (currentPressure < lastPressure) {
            System.out.println("注意降温,阴云多雨天气");
        }
    }
}

测试类

package TestMain;



import Implements.CurrentConditionDisplay;
import Implements.ForecastDisplay;
import Implements.WeatherData;

public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        
        CurrentConditionDisplay ccd = new CurrentConditionDisplay(weatherData);
        ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
        //第一次天气情况
        weatherData.setMeasurements(80f, 65f, 30.4f);
        System.out.println();
        //第二次天气情况
        weatherData.setMeasurements(82f, 70f, 29.2f);
        System.out.println();
        //第三次天气情况
        weatherData.setMeasurements(78f, 90f, 29.2f);
        
    }
}

运行效果

要点:
1:观察者模式定义了对象之间一对多的关系。
2:主题用一个共同接口来更新观察者。(update方法和Subject接口)
3:观察者和可观察者(主题)之间用松耦合的方式结合,可观察者(主题)不知道观察者的细节,只知道观察者实现了观察者接口。
4:Java内置了观察者模式的实现。

自此完成了观察者模式的实例,Java在JDK当中内置主题和观察者的用法,这里为了更好理解,所以我写的是自定义的形式,
这个模式理解起来并不难,但却是个非常有用的模式,你现在就可以试着用观察者和策略模式改改以前写的旧代码,我的感受就是随着学习深入,就觉得以前写的代码很多都是有错误的。。。。。

感谢你看到这里,观察者模式部分结束,本人文笔随便,若有不足或错误之处望给予指点,90度弯腰~很快我会发布下一个设计模式内容,生命不息,编程不止!

参考书籍:《Head First 设计模式》

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67612.html

相关文章

  • 设计模式(通往高手之路的必备技能)

    摘要:设计模式的定义在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案。从前由于使用的局限性,和做的应用相对简单,不被重视,就更谈不上设计模式的问题。 ‘从大处着眼,从小处着手’,以前对这句话一知半解,自从踏出校门走入社会,开始工作以来,有了越来越深的理解,偶有发现这句话用在程序开发中也有用,所以,近段时间开始尝试着分析jQuery源码,分析angularjs源码,学习设计模式。 设...

    paraller 评论0 收藏0
  • 开发之路设计模式三:装饰者模式

    摘要:若要扩展功能,装饰者提供了比继承更有弹性的替代方案。装饰者模式意味着一群装饰者类,这些类用来包装具体组件。装饰者类反映出被装饰组件类型。装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。 嘿嘿嘿,你是不是很喜欢用继承呢?感觉没什么事情是一个爸爸类搞不定的,有的话就两个,快来跟我看看这个模式吧,它能让你断奶,给爱用继承的人一个全新的设计眼界。 直奔主题,你是否有听说...

    Vicky 评论0 收藏0
  • php设计模式

    摘要:我们今天也来做一个万能遥控器设计模式适配器模式将一个类的接口转换成客户希望的另外一个接口。今天要介绍的仍然是创建型设计模式的一种建造者模式。设计模式的理论知识固然重要,但 计算机程序的思维逻辑 (54) - 剖析 Collections - 设计模式 上节我们提到,类 Collections 中大概有两类功能,第一类是对容器接口对象进行操作,第二类是返回一个容器接口对象,上节我们介绍了...

    Dionysus_go 评论0 收藏0
  • php设计模式

    摘要:我们今天也来做一个万能遥控器设计模式适配器模式将一个类的接口转换成客户希望的另外一个接口。今天要介绍的仍然是创建型设计模式的一种建造者模式。设计模式的理论知识固然重要,但 计算机程序的思维逻辑 (54) - 剖析 Collections - 设计模式 上节我们提到,类 Collections 中大概有两类功能,第一类是对容器接口对象进行操作,第二类是返回一个容器接口对象,上节我们介绍了...

    vspiders 评论0 收藏0

发表评论

0条评论

n7then

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<