设计模式-观察者模式(读书笔记)
?? 最近在学习设计模式,特将学习的内容自我总结下,希望能和大家分享,并得到指正。首先分享观察者模式。
?
一、定义。
??? 定义了对象之间的一对多的依赖,当一个对象发生改变时,它的所有依赖者都会收到通知并自动更新。如果对观察者模式不是很清楚的朋友,估计初看这个定义可能收获的会比较模糊。其实用通俗的话来说的话,其实就是表示一个一对多的结构。其中一代表一个主题,是产生消息的;而多则是需要接受消息,就是观察者了。书上举了一个很简单的例子,由气象局来代表主题,由它来产生气象信息,而这个气象消息可能需要不同的方式去展示,则每一种展示气象消息的媒介则就是每一个依赖于气象局的观察者了,因为要获取最新消息只能找气象局。
?
二、观察者的实现。
??? 书中是先讲主题的,但是我觉得观察者更简单一些,所有还是先说一下观察者。这里是通过一个接口来定义的。
public interface Observer {void update(Subject subject,Object obj);}
比较简单,只有一个update方法,其中有两个参数,其中的subject是其所依赖的主题,而obj则是主题更新时传递过来的消息。每次发现有更新后会自动执行观察者的update方法将信息传递过来。
?
三、主题的实现。
??? 同样也是通过接口定义,毕竟能面向接口编程,就少用继承。
public interface Subject {/** * 注册一个观察者 * @param observer */void addObserver(Observer observer);/** * 删除一个观察者 * @param observer */void removeObserver(Observer observer);/** * 发起通知观察者的动作 */void notifyObserver();}
也是较为简单,其中也就最基本的三个方法。下面看一下具体实现吧。
public class SubJectTest implements Subject {private boolean change;private List<Observer> observerList;private Object paramObject;public SubJectTest(){this.observerList=new ArrayList<Observer>();}public void addObserver(Observer observer) {int i=this.observerList.indexOf(observer);if(i<0){this.observerList.add(observer);}else{System.out.println("is exist");}}public void notifyObserver() {if(change){for (Observer ob:observerList) {ob.update(this,paramObject);}this.makeChange(false);}}public void removeObserver(Observer observer) {int i=this.observerList.indexOf(observer);if(i!=-1){this.observerList.remove(observer);}else{System.out.println("is not exist");}}public void makeChange(boolean change){this.change=change;}public void updateInfo(Object obj){this.paramObject=obj;this.notifyObserver();}}
1、使用一个ArryList来存放注册的观察者。在构造方法中进行初始化。
?
2、其中还定义了一个change变量,在通知其所有的观察者前会先判断这个变量。其存在的意义时,也许主题并不是每一次改变都需要进行通知观察者,可以自己灵活控制。比如说,气象局对天气信息可能每1分钟就能更新一次,但是真正需要显示时的也许每天只需要通知一次而已。
?
3、updateInfo就是气象局自己更新了obj时,直接调用就好了,当change满足条件时,则会自动通知其依赖的所有的观察者。
?
4、makeChange则是你自己认为需要通知观察者时,改变其状态好了。
其结构也是相对较为简单的。那么下面实现两个简单的观察者好了,用来接收气象信息。
?
四、观察者的实现。
1、电视方式展示气象信息。
/* * 电视方式展示气象信息 */public class CCTVObserver implements Observer {public void update(Subject subject, Object obj) {System.out.println("CCTV:"+obj);}}
?
2、短信方式展示气象信息。
/* * 短信方式展示气象信息 */public class MessageObserver implements Observer {public void update(Subject subject, Object obj) {System.out.println("Message:"+obj);}}
?
五、测试。。
public class MainTest {/** * @param args */public static void main(String[] args) {/* * 创建主题 */SubJectTest subject=new SubJectTest();/* * 创建观察者 */Observer cctv=new CCTVObserver();Observer message=new MessageObserver();/* * 注册观察者 */subject.addObserver(cctv);subject.addObserver(message);//认为可以通知subject.makeChange(true);subject.updateInfo("成都地区,今天晴转多云,最高气温29度,最低气温15度,风力三级");}}
?
运行结果:
CCTV:成都地区,今天晴转多云,最高气温29度,最低气温15度,风力三级
Message:成都地区,今天晴转多云,最高气温29度,最低气温15度,风力三级
?
五、通过jdk自带API实现观察者模式。
?? jdk提供了java.util.Observable来定义主题,注意这个一个类,而不是接口。而提供java.util.Observer接口来定义接口,和我们自已定义的相同,只有一个update方法。
1、实现主题。
public class Subject extends java.util.Observable {public void updateInfo(Object obj){super.setChanged();this.notifyObservers(obj);}}
可以看出,很简单了,注册呀删除呀事情,父类都帮你做了。你只要自己实现逻辑,需要通知时调用notifyObservers方法就好了。注意父类的makeChange是protected的,所有只有子类才能调用。
?
2、其他的实现和我们定义的就完全相同了,没有什么太大的改变。
/* * 电视方式展示气象信息 */public class CCTVObserver implements java.util.Observer {public void update(Observable o, Object arg) {System.out.println("CCTV:"+arg);}}
?
/* * 短信方式展示气象信息 */public class MessageObserver implements java.util.Observer {public void update(Observable o, Object arg) {System.out.println("Message:"+arg);}}
?
public static void main(String[] args) {/* * 创建主题 */Subject subject=new Subject();/* * 创建观察者 */Observer cctv=new CCTVObserver();Observer message=new MessageObserver();/* * 注册观察者 */subject.addObserver(cctv);subject.addObserver(message);//认为可以通知subject.updateInfo("成都地区,今天晴转多云,最高气温29度,最低气温15度,风力三级");}
?
?
运行结果:
Message:成都地区,今天晴转多云,最高气温29度,最低气温15度,风力三级
CCTV:成都地区,今天晴转多云,最高气温29度,最低气温15度,风力三级
?
但是这样看,貌似使用jdk自带的观察者要简单一些。
?
六、jdk观察者的一些问题。
1、首先Observable不是接口。这个比较郁闷,毕竟继承了它就不能集成其他类了。
2、仔细的朋友可以看出两次运行结果的顺序不同。Observable注册的顺序和通知的顺序不同。从这点看出,灵活性不强。
?
附件为具体的代码。。