观察者模式在Java语言中的地位极其重要,JDK也提供了对观察者模式的内置支持,实现思路是:Observable类用于创建主题类,当这种子类的对象发生变化时,观测类被通知,观测类必须实现定义了update()方法的Observer接口。 当一个观测程序被通知到一个被观测对象的改变时,update()方法被调用。
下面学习到自己搭建观察者模式的步骤:
1、创建两个接口,一个是抽象的主题角色(被观察的对象),一个是抽象的观察者角色。
package observer;
/*
* 抽象的主题角色
*/
public interface Watched
{
//这里Watcher是一个接口
public void addWathcer(Watcher watcher);
public void removeWatcher(Watcher watcher);
public void notifyWatchers(String str);
}
package observer;
/*
* 抽象的观察者角色
*/
public interface Watcher
{
public void update(String str);
}
2、创建两个角色的实现类
package observer;
import java.util.ArrayList;
import java.util.List;
public class ConcreteWatched implements Watched
{
//创建一个集合,用来承载观察自己的观察者们
private List<Watcher> list = new ArrayList<Watcher>();
@Override
public void addWathcer(Watcher watcher)
{
list.add(watcher);
}
@Override
public void removeWatcher(Watcher watcher)
{
list.remove(watcher);
}
//主题对象在此处调用观察者对象,在AWT中是在内部实现,外部看不到,会误以为是自动调用,其实是由主题调用
@Override
public void notifyWatchers(String str)
{
for(Watcher watcher : list)
{
watcher.update(str);
}
}
}
package observer;
public class ConcreteWatcher implements Watcher
{
@Override
public void update(String str)
{
System.out.println(str);
}
}
3、创建测试类,实现观察者模式
package observer;
public class test
{
public static void main(String[] args)
{
/*
* 对应到AWT模型中,观察者模式就容易理解了
*/
//相当于按钮
Watched origin = new ConcreteWatched();
Watcher watcher1 = new ConcreteWatcher();
Watcher watcher2 = new ConcreteWatcher();
Watcher watcher3 = new ConcreteWatcher();
//相当于添加监听器
origin.addWathcer(watcher1);
origin.addWathcer(watcher2);
origin.addWathcer(watcher3);
//相当于点击按钮
origin.notifyWatchers("First notity");
origin.removeWatcher(watcher3);
origin.notifyWatchers("Second notify");
}
}
在学习过程中,对观察者模式的理解,最重要的在于第2步中主题对象调用观察者对象,通过遍历所有观察者,实现观察者中的方法。其次还有主题中使用集合建立与观察者之间的关联。
由于观察者模式在AWT,swing中使用很广泛,学习观察者模式有助于swing中按钮添加监听事件的原理,并不是自动实现方法调用,而是作为主题的按钮实现了对事件的调用。
通过练习观察者模式,进一步体会到了接口的作用(因为单纯的看这个例子不禁会想到-为什么明明可以用类直接实现的,还要多设计两个接口,接口(抽象主题、观察者角色)在这里的作用是什么?):
原由:在创建主题类和观察者类时,完全可以不使用接口,如下:
ConcreteWatched origin = new ConcreteWatched();
ConcreteWatcher watcher1 = new ConcreteWatcher();
ConcreteWatcher watcher2 = new ConcreteWatcher();
ConcreteWatcher watcher3 = new ConcreteWatcher();
解释:
此处也是多态的使用,在这个例子中只对Watched和Watcher接口实现了一种类,没有体现出使用接口的优势
如果有多个方法相同的类而不使用接口,创建不同主题角色,就要改变一次其参数类型,看上去很混乱
如: ConcreteWatched1:public void addWathcer(ConcreteWatcher1 watcher){}
ConcreteWatched2:public void addWathcer(ConcreteWatcher2 watcher){}
而利用接口抽象出来后,主题角色的参数类型用接口表示就无需改变其参数类型,只需实现本身的功能就可以
ConcreteWatched1:public void addWathcer(Watcher watcher){}
ConcreteWatched2:public void addWathcer(Watcher watcher){}
说到底,就是接口在java中的作用:
达到统一访问,就是在创建对象的时候用接口创建,
【接口名】【对象名】 = new 【实现接口的类】,
这样用哪个类的对象就可以new哪个对象了,不需要改原来的代码。
主要体现在多个类实现同一个接口时,统一访问的优势才会发挥出来
而且,在使用时,多态的使用使代码更整齐易懂