观察者模式

xiaoxiao2021-02-27  337

观察者模式对象间建立一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。 观察者模式可在主题处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 设计模式

转载请注明原文地址: https://www.6miu.com/read-2424.html

最新回复(0)