Java设计模式之观察者模式
2018-03-23 13:42
423 查看
Java设计模式,又称为java管理模式,一切的设计都只是为了更好地管理某些事物(使得代码不重复累赘)。
注:(1)Vector 是在 java 中可以实现自动增长的对象数组。
(2)在面向对象的概念里推荐的一条就是面向接口编程,所以在实际使用的时候好的编程习惯就应该针对接口去写实现。例如:动物有:天上飞,陆上跑,水里游。
对于陆地上的动物,实现“路上跑”接口,但是两栖动物就是实现2个接口。
使用的时候就通过水里游或者路上跑这样的接口去调用实际的方法。
引用: IA a = new A();
强制类型转换:A = (A)a;
(3)attribute和property在英语里有什么区别?
Property在英语里有财产的含义,一般指对象的组成部分,可以是简单数据也可以是对象或对象集合. Attribute多指一个对象的特征,绝大的数情况下是一个描述性的数据。
(4)comment,计算机专业术语,表示 HTML 或 XML 文档中的注释节点 的内容。
(5)Map集合中的entry是什么?
Map是
关键代码(【one-to-many】 【一个主题对象-管理-多个观察者对象】的【创建和更新数据】 )
(1)观察者接口IObserver public interface IObserver{ public void response(String data); //更新一下通知的内容 } (2)主题接口ISubject public interface ISubject{ public void register(IObserver obr); //注册观察者 public void unregister(IObserver obr); //注销观察者 public void notifyObservers(); //通知所有观察者 } (3)主题实现类 public class Subject implements ISubject { private Vector<IObserver> vec = new Vector(); //观察者对象的维护向量(一个可以自增的观察者数组) private String data; //主题的中心数据 public String getData(){return data;} public String setData(String data){this.data = data;} public void register(IObserver obr){ vec.add(obr); //主题注册(添加)观察者 } public void unregister(IObserver obr){ if(vec.contains(obr)) vec.remove(obr); //主题注销(删除)观察者 } public void notifyObservers(){ for(int i = 0; i < vec.size(); i++){ IObserver obr = vec.get(i); //遍历一下观察者数组 obr.response(data); //【主题通知所有观察者进行数据的接收和响应】 } } } (4)一个具体观察者类Observer public class Observer implements IObserver { public void response(String data){ System.out.printIn("我接收到主题的数据:"+data); } } (5)一个简单的测试类Test public class Test{ public static void main (String[] args){ IObserver obr = new Observer(); //定义观察者对象 ISubject sub = new Subject(); //定义主题对象 sub.register(obr); //主题添加观察者 sub.setData("hello"); //主题中心数据发生变动 sub.notifyObservers(); //通知所有观察者接收数据并进行数据响应 } }
泛型接口
注意:上文的data是String类型的,若改为其他类型,则IObserver接口等相关代码都需要进行修改。其实,只要把ISubject、IObserver接口改为泛型接口就可以了。这样参数T就必须是类类型,不能是基本数据类型,如不能是int,但可以是Integer。
改为: (1)观察者泛型接口IObserver<T> public interface IObserver<T>{ public void response(T data); } (2)主题泛型接口ISubject<T> public interface ISubject<T>{ public void register(IObserver<T> obr); public void unregister(IOservser<T> obr); public void notifyObservsers(); }
“拉”数据【一个观察者对象 管理 一个主题对象】
注意:上文中观察者的data是主题对象直接“推”送给观察者的;但是我们需要的是观察者自己主动去向主题对象“拉”数据。
改为: (1)观察者【主动型】接口IObserver public interface IObserver{ public void response(ISubject obj); //【为了防止耦合,此处参数类型设为主题接口】 } (2)主题接口ISubject public interface ISubject{ public void register(IObserver obr); public void unregister(IObserver obr); public void notifyObservers(); } (3)主题实现类 public class Subject implements ISubject { //。。。 public void notifyObservers(){ for(int i = 0; i < vec.size(); i++){ IObserver obr = vec.get(i); obr.response(this); //【this指当前subject对象,代替原来的data】 } } } (4)一个具体观察者类Observer public class Observer implements IObserver { public void response(ISubject obj){ //主题接口obj是通过【参数引用】的方式引用了主题对象 Subject subject = (Subject)obj; //必须进行强制类型转换 System.out.printIn("我接收到主题的数据:"+subject.getData()); } }
增加父类层AbstractSubject
假设有多个主题类,且每个主题类的方法都是相同的,那么为了不重复register、unregister和notifyObsertvers方法,我们用父类层(封装了这三个方法)来解决代码重复问题。
改为: (1)增加的父类层AbstractSubject【封装了这三个方法,然后子类Subject在继承了此类的同时也继承了这三个方法】 public class AbstractSubject implements ISubject{ Vector<IOserver> vec = new Vector(); public void register(IObserver obr){ vec.add(obr); } public void unregister(IObserver obr){ if(vec.contains(obr)) vec.remove(obr); } public void notifyObserver(){ for(int i=0; i < vec.size(); i++){ IObserver obr = vec.get(i); obr.response(this); } } } (2)派生主题类Subject public class Subject extends AbstractSubject{ private Integer data; public Integer getData(return data;} public void setData(Integer data){this.data = data;} }
避免重复添加同一类型的观察者对象
IObserver obr1 = new Observer(); IObserver obr2 = new Observer(); Subject sub = new Subject(); sub.register(obr1); sub.register(obr2);
其中obr1和obr2是同一类型的观察者对象,但它们的物理地址是不同的,
最重要的是Vector类的contains()方法默认是物理查询,因此它们仍然都添加到了vec中,怎么办?
解决办法是【我们需要一个【MARK标志常量】来标记各自的观察者类型】,以便通过逻辑运算符【==】来判断MARK是否相等。
改为: (1)添加了【getMark()多态方法】的观察者接口IObserver public interface IObserver{ public int getMark(); //... } (2)添加了【MARK标志常量】的观察者类 第一个类型的观察者类: public class Observer1 implements IObserver{ private final int MARK = 1; public int getMark(){return MARK;} public boolean equals(Object arg0){ Observer obr = (Observer)arg0; return obr.getMark() == MARK; } //... } 第二个类型的观察者类: public class Observer2 implements IObserver{ private final int MARK = 2; public int getMark(){return MARK;} public boolean equals(Object arg0){ Observer obr = (Observer)arg0; return obr.getMark() == MARK; } //... }
注解:为什么在观察者接口IObserver中必须添加一个多态方法getMark()?
因为register()方法的参数是IObserver类型,所以在IObserver中必须有一个getMark()方法来获取MARK值。
反射技术的应用
将观察者类信息封装在xml配置文件中,从而利用反射技术可以动态加载观察者对象。配置文件采用键值配对形式,值对应的是具体观察者的类名称。由于键是关键字,不能重复,为了编程方便,键采用“统一前缀+流水号”的形式,配置文件示例如下表:说明: 键前缀“observer” 和 键流水号“1,2,3,...” xml配置文件: <?xml version="1.0" encoding = "utf-8" standalone="no"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>Observer</comment> <entry key="observer1">Observer1</entry> <entry key="observer2">Observer2</entry> </properties> 具体程序代码如下: public interface IObserver{//同上文} public interface ISubject{ public void register(String strXMLPath); //表明从配置文件加载观察者对象 public void unregister(IObserver obr); public void notifyObservers(); } //主体类Subject public class Subject implements ISubject{ //其他代码同上文 public void register(String strXMLPath){ String prefix = "observer"; String observerClassName = null; Properties p = Properties(); try{ FileInputStream in = new FileInputStream(strXMLPath); p.loadFormXML(in); int n = 1; while((observerClassName = p.getProperty(prefix+n))!=null){ Constructor c = Class.forName(observerClassName).getConstructor(); IObserver obr = (IObserver)Class.forName(observerClassName).newInstance(); vec.add(obr); n++; } in.close(); }catch(Exception e){ e.printStackTrace(); } } } //一个具体观察者类Observer public class Observer1 implements IObserver{//同上文} public class Observer2 implements IObserver{//同上文} //一个简单的测试类 public class Test{ public static void main(String[] args) throws Exception{ Subject sub = new Subject(); //定义主题对象 sub.register("d:/config/info5.xml"); //主题通过配置文件加载观察者对象 sub.setData("hello"); //主题数据变化了 sub.notifyObservers(); //通知各个观察者对象进行数据响应 } }
JDK中的观察者设计模式
JDK的java.until包提供了系统的主题类Observable以及观察者接口Observer应用探究
机房温度监测仿真功能。分析:监测功能是以温度为中心的,因此用观察者设计模式实现程序架构是比较方便的。
总体思想是:温度作为主题类,两个观察者类,一个观察者负责记录数据,另一个观察者负责异常处理。
相关文章推荐
- java设计模式-观察者模式
- Java设计模式之观察者模式(Observer)
- 浅谈Java设计模式(十五)观察者模式(Observer)
- Java设计模式--观察者模式
- Java设计模式----观察者模式(Observer)
- java 观察者模式设计方法
- Java设计模式之观察者模式
- Java 设计模式之-观察者模式
- java设计优化--观察者模式
- java观察者设计模式
- 设计模式--观察者模式初探和java Observable模式
- Java设计模式-------观察者模式
- java设计模式之观察者模式
- Java设计模式--观察者模式
- Java设计模式之观察者模式
- JAVA设计模式之:观察者模式
- java设计模式---观察者模式
- Java设计模式(15)行为型:观察者模式
- Java设计模式之观察者模式
- 设计模式--观察者模式初探和java Observable模式