- package observer;
- /**
- * 观察主题
- */
- public interface Observable{
- public void addObserver(Observer observer);//添加观察者
- public void removeObserver(Observer observer);//移除观察者
- public void notifyObservers(WeatherData data);//通知所有观察者
- }
观察主题也可以是抽象类,具体可以参考 java.util.Observable,这里就不展开来 bb 了。
那么什么时候选择抽象类,什么时候选择接口呢?
我的理解是,这个就要看,代价高不高了,抽象类的好处就是,可以少写代码,实现复用。接口可以应对各种不同的变化,因为观察者并不一定有共同使用的实现类,可能它们完全就是不同的东西。
这个地方我只有一个主题,我想用什么就用什么,就是这么任性,如果以后出了第二个或者第三个主题,那么就可以考虑具体是抽象类还是接口了,当然也不排除两种都用的情况。当然这是后话,程序本来就是不断变化的,适当的时候用适当的设计才是王道。
- package observer;
- /**
- * 观察者
- */
- public interface Observer {
- public abstract void update(WeatherData data);
- }
- package observer;
- /**
- * 天气数据
- */
- public class WeatherData {
- private float temperature;
- private float humidity;
- private float pressure;
- public WeatherData(){
- }
- public WeatherData(float temperature, float humidity, float pressure){
- this.temperature = temperature;
- this.humidity = humidity;
- this.pressure = pressure;
- }
- }
getter,setter 省略,不然篇幅太长了
在 Observer 这个接口里面,我的 update() 方法里面带了一个 WeatherData 对象,为什么不是 Object 呢,为什么不是直接三个参数,温度,湿度,气压呢?我当时想了很久(我也是一边看书,一遍写的,不是把所有的都学完了才来写博客的,所以不懂的多了去了)
用 Object 的好处当然是不仅更新天气可以用这个,以后更新其他什么的也可以用,而且,如果我 update 方法里面的需求有了新的变化,比如,我要更新时间,那么,这个参数总不能放在 WeatherData 里面吧,好不符合逻辑啊,强迫症怎么受得了???
思来想去我的理解是这样的:
1,这个是一个气象站应用,那么应该就是存气象数据吧,这个总没问题嘛
2,写一个 Object 会不会被后面接替我工作的同事砍死啊,Object 里面是什么,通过方法名根本就看不出来,必须去具体的代码里面看,万一我逻辑有点复杂,注释再少点,那他不就懵逼了?
3,不直接用三个参数也是为了以后的变化,万一变成 5 个参数咋办?改都改死人,而且要是 5 个都是 float 类型,好容易在传的时候传错,发现得早还好,万一传错了,但是又通过测试了怎么办呢?
肯定有人觉得这不可能,那我举个例子
接口的定义是:
void test(int a, int b, int c);
实现是 void test(int a, int c, int b){...}
调用接口的时候,传入的是 test.test(a, c, b); 那么请问,这个能通过测试吗?可以的。后面的人会掉坑里吗?我觉得他只要去改代码,那么就很有可能,嘿嘿嘿
- package observer;
- /**
- * 显示
- */
- public interface DisplayElement {
- void display();
- }
这个接口没什么解释的,就是显示用的,下面我要大段贴代码了
- package observer;
- /**
- * 当前天气状况*/
- public class CurrentConditionsDisplay implements DisplayElement, Observer {
- Observable observable;
- public CurrentConditionsDisplay(Observable observable) {
- this.observable = observable;
- }
- WeatherData data = new WeatherData();
- @Override
- public void display() {
- System.out.println("当前的天气状况: " +
- "温度(℉):" + data.getTemperature() + " " +
- "湿度:" + data.getHumidity() + " " +
- "气压:" + data.getPressure());
- }
- @Override
- public void update(WeatherData data) {
- this.data = data;
- display();
- }
- }
- package observer;
- /**
- * 天气统计
- *
- */
- public class StatisticsDisplay implements DisplayElement, Observer {
- private Float average;
- private Float highest;
- private Float lowest;
- @Override
- public void display() {
- System.out.println("天气统计:" +
- "平均温度(℉):" + average + " " +
- "最高温度(℉):" + highest + " " +
- "最低温度(℉):" + lowest);
- }
- @Override
- public void update(WeatherData data) {
- float temperature = data.getTemperature();
- average = null == average ? temperature :
- (average + temperature) / 2;
- highest = null == highest ? temperature :
- (highest > temperature ? highest : temperature);
- lowest = null == lowest ? temperature :
- (lowest > temperature ? temperature : lowest);
- display();
- }
- }
- package observer;
- /**
- * 天气预报*/
- public class ForecastDisplay implements DisplayElement, Observer {
- private float pressure;
- @Override
- public void update(WeatherData data) {
- pressure = data.getPressure();
- display();
- }
- @Override
- public void display() {
- System.out.println("天气预测:" + forecast());
- }
- private static final float INFRABAR = 28.5f;//气压低就会下雨
- private String forecast(){
- return INFRABAR < pressure ? "明天不下雨" : "明天要下雨";
- }
- }
- package observer;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * 天气主题
- *
- */
- public class Weather implements Observable {
- private List observers = new ArrayList<>();;
- public void addObserver(Observer observer) {
- observers.add(observer);
- }
- public void removeObserver(Observer observer) {
- observers.remove(observer);
- }
- public void notifyObservers(WeatherData data) {
- for (Observer observer : observers)
- observer.update(data);
- }
- }
- package observer;
- /**
- * 测试
- * @author Skysea
- *
- */
- public class Client {
- public static void main(String[] args) {
- Observable observable = new Weather();
- Observer currentCondition = new CurrentConditionsDisplay(observable);
- Observer statistics = new StatisticsDisplay();
- Observer forecast = new ForecastDisplay();
- observable.addObserver(currentCondition);
- observable.addObserver(statistics);
- observable.addObserver(forecast);
- observable.notifyObservers(new WeatherData(80, 65, 30.4f));
- observable.notifyObservers(new WeatherData(82, 70, 29.2f));
- observable.notifyObservers(new WeatherData(78, 90, 25.1f));
- }
- }
运行结果:
在测试代码中,添加观察者到主题这些代码,也是可以放在观察者中去实现的,在初始化的时候就把自己加入到主题的列表中
在实际的使用中,如使用 Spring 的依赖注入之类的,还是很好用的,也可以省很多事情,最后的交互方式大概是这个样子
- package observer;
- /**
- * 测试2
- */
- public class Client2 {
- @Autowired
- private Observable observable;
- public static void main(String[] args) {
- observable.notifyObservers(new WeatherData(80, 65, 30.4f));
- observable.notifyObservers(new WeatherData(82, 70, 29.2f));
- observable.notifyObservers(new WeatherData(78, 90, 25.1f));
- }
- }
嗯,没错,什么初始化都没有了,观察者在启动的时候就注入到主题中了,只需要调用主题的接口就好了,而主题也仅仅是持有了一个 List<Observer> observers; 具体的观察者是谁它也不知道,但是它们还是可以相互交互,是不是很酷?
好了,我 bb 完了,本系列的大部分所有例子,都是在看 headfirst 设计模式时,看到的,并加入自己的理解写下来的(当然我也编了一些),写这段话的目的也是为了避免一些不必要的误会,以后的每期我都会复制这段话,哈哈哈
来源: