观察者模式

观察者模式对象间建立一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。
观察者模式可在主题处push或者pull数据,push方式被认为更正确的方式。以下第一个实例中用push,第二个用pull。

java类图

这里写图片描述

java代码

// 主题接口
public interface Subject {
    void register(Observer observer);

    void remove(Observer observer);

    void notifyObserver();
}

// 主题
public class WeatherData implements Subject {

    private ArrayList<Observer> observers;

    private int temperature;
    private int humidity;
    private int pressure;

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

    @Override
    public void register(Observer observer) {
        if (!observers.contains(observer)) {
            observers.add(observer);
        }
    }

    @Override
    public void remove(Observer observer) {
        int index = observers.indexOf(observer);
        if (index >= 0) {
            observers.remove(index);
        }
    }

    @Override
    public void notifyObserver() {
        for (Observer observer : observers) {
            // 通知所有订阅的观察者,主动将数据推送给观察者
            observer.update(temperature, humidity, pressure);
        }
    }

    public void setData(int temperature, int humidity, int pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        // 数据改变后会调用notifyObserver方法
        notifyObserver();
    }
}

// 展示接口,与模式无关
public interface Display {
    void display();
}

// 观察者接口
public interface Observer {
    void update(int temperature, int humidity, int pressure);
}

// 天气情况展示板
public class WeatherDisplay implements Observer, Display {

    // 方便取消订阅
    private Subject subject;

    private int temperature;
    private int humidity;
    private int pressure;

    public WeatherDisplay(Subject subject) {
        this.subject = subject;
        // 新建展示板时,订阅主题
        subject.register(this);
    }

    @Override
    public void display() {
        System.out.println("temperature=" + temperature + ", humidity=" + humidity + ", pressure=" + pressure);
    }

    @Override
    public void update(int temperature, int humidity, int pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        // 主题变化时调用update,display展示内容
        display();
    }
}

// 天气改变展示板
public class ChangeDisplay implements Observer, Display {
    // 方便取消订阅
    private Subject subject;

    private int temperature;
    private int humidity;
    private int preTemperature;
    private int preHumidity;

    public ChangeDisplay(Subject subject) {
        this.subject = subject;
        subject.register(this);
    }

    @Override
    public void display() {
        System.out.println("temperatureChange=" + displayCal(temperature, preTemperature) + ", humidityChange=" + displayCal(humidity, preHumidity));
    }

    public String displayCal(int now, int pre) {
        int difference = now - pre;
        if (difference > 0) {
            return "↑";
        } else if (difference < 0) {
            return "↓";
        } else {
            return "-";
        }
    }

    @Override
    public void update(int temperature, int humidity, int pressure) {
        preTemperature = this.temperature;
        preHumidity = this.humidity;
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }
}

// 测试类
public class Test {
    public static void main(String[] args) {
        new Test().test();
    }

    private void test() {
        WeatherData weatherData = new WeatherData();
        WeatherDisplay weatherDisplay = new WeatherDisplay(weatherData);
        ChangeDisplay changeDisplay = new ChangeDisplay(weatherData);

        weatherData.setData(10, 23, 2);
        weatherData.setData(8, 24, -1);

    }
}

注:

主题直接将数据推送给观察者,属于push方式
观察者模式定义了对象间的一对多关系
主题用一个共同的接口来更新观察者
观察者和可观察者之间用松耦合方式结合,可观察者不知道观察者的细节,只知道观察者实现了观察者接口
有多个观察者时,不可以依赖特定的通知顺序


java自带观察者接口

类图

这里写图片描述

java代码

// 主题
public class WeatherData extends Observable {  // 采用继承的方式

    private int temperature;
    private int humidity;
    private int pressure;

    public void setData(int temperature, int humidity, int pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        // 需要设置标记才能通知观察者
        setChanged();
        // 通知观察者并传递一个object对象
        notifyObservers("push object");
    }

    public int getTemperature() {
        return temperature;
    }

    public int getHumidity() {
        return humidity;
    }

    public int getPressure() {
        return pressure;
    }
}

// 展示接口
public interface Display {
    void display();
}

// 天气情况展示板
public class WeatherDisplay implements Observer, Display {

    // 方便取消订阅
    private Observable observable;

    private int temperature;
    private int humidity;
    private int pressure;

    public WeatherDisplay(Observable observable) {
        this.observable = observable;
        observable.addObserver(this);
    }

    @Override
    public void display() {
        System.out.println("temperature=" + temperature + ", humidity=" + humidity + ", pressure=" + pressure);
    }


    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof WeatherData) {
            WeatherData weatherData = (WeatherData) o;
            // 主题推送自己的引用,观察者需要自己去主题中获取数据
            this.temperature = weatherData.getTemperature();
            this.humidity = weatherData.getHumidity();
            this.pressure = weatherData.getPressure();
            System.out.println("Object arg is " + arg);
            display();
        }
    }
}

// 天气改变展示板
public class ChangeDisplay implements Observer, Display {

    // 方便取消订阅
    private Observable observable;

    private int temperature;
    private int humidity;
    private int preTemperature;
    private int preHumidity;

    public ChangeDisplay(Observable observable) {
        this.observable = observable;
        observable.addObserver(this);
    }

    @Override
    public void display() {
        System.out.println("temperatureChange=" + displayCal(temperature, preTemperature) + ", humidityChange=" + displayCal(humidity, preHumidity));
    }

    public String displayCal(int now, int pre) {
        int difference = now - pre;
        if (difference > 0) {
            return "↑";
        } else if (difference < 0) {
            return "↓";
        } else {
            return "-";
        }
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof WeatherData) {
            WeatherData weatherData = (WeatherData) o;
            preTemperature = this.temperature;
            preHumidity = this.humidity;
            this.temperature = weatherData.getTemperature();
            this.humidity = weatherData.getHumidity();
            System.out.println("Object arg is " + arg);
            display();
        }
    }
}

// 测试类
public class Test {
    public static void main(String[] args) {
        new Test().test();
    }

    private void test() {
        WeatherData weatherData = new WeatherData();
        WeatherDisplay weatherDisplay = new WeatherDisplay(weatherData);
        ChangeDisplay changeDisplay = new ChangeDisplay(weatherData);

        weatherData.setData(10, 23, 2);
        weatherData.setData(8, 24, -1);

    }
}

注:

主题将自己的引用推送给观察者,观察者主动从主题中获取数据,属于pull方式
java.util.Observable是一个类,无法自定义实现,而且也无法再继承其他类。

参考文章
Head First 设计模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值