文章摘要
1、松耦合神器-观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并更新。----HeadFirst设计模式
2、松耦合的设计之所以能够让我们建立有弹性的OO系统,应对变化,便于扩展和维护,就是应为它将对象之间的互相依赖降到了最低。
说到观察者模式,我们之前已经分享过Android中的一个案例《Cursor和CursorAdapter中的观察者模式机制#360》,下面我们就通过一个简易的案例来认识下这个模式及其用法。
一、模式总结:
观察者模式提供了一中松耦合的代码设计,当两个对象松耦合时,他们依然可以交互,但是不清楚彼此的细节。观察者模式提供了一种对象设计,让主题和观察者模式之间可以松耦合。关于观察者的一切,主题只知道观察者模式实现了某个接口,主题也不必知道观察者的具体类是谁,做了什么。任何时候我们都可以增加、删除观察者,并且主题不受影响。因为主题唯一依赖的是实现了Observer接口的对象。
观察者模式让后续程序维护更加灵活。当有新类型的观察者出现时,我们不必须为了兼容新类型而去修改主题,我们只需让新类型观察者实现Observer接口,然后注册成为观察者。主题只会发送通知给所有实现了观察者接口的对象。
松耦合的设计之所以能够让我们建立有弹性的OO系统,应对变化,便于扩展和维护,就是因为它将对象之间的互相依赖降到了最低,修改一方,不会影响到另一方。
二、UML类图
三、观察者模式的类比以及理解
观察者模式又叫订阅者模式,大家可以想象:订阅<<南方周末>>,是不是每当南方周末发版,都会收到其报纸。
Android系统中的观察者实例
广播接受者:BroadcastReceiver
ContentResolver.registerContentObserver
四、观察者模式案例
1、主题接口Observable.java,观察者接口Observer.java
public interface Observable {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver();
}
public interface Observer {
public void update(Observable o,Object obj);
}
2、小花猫和猫头鹰以捉老鼠为生。现在有一个广播老鼠信息的主题。
Subject.java 主题,实现了Observable,发现老鼠,进行广播。
import java.util.ArrayList;
public class Subject implements Observable{
private ArrayList<Observer> mValues = new ArrayList<Observer>();
private Content mBody = new Content();
public Subject(){
}
@Override
public void registerObserver(Observer o) {
mValues.add(o);
}
@Override
public void removeObserver(Observer o) {
mValues.remove(o);
}
@Override
public void notifyObserver() {
for(Observer o :mValues){
o.update(this, mBody);
}
}
public void findMouse(String name,int num){
Content content = new Content(name, num);
mBody = content;
notifyObserver();
}
class Content{
private String mName;
private int mNum;
public Content(){
this(null,0);
}
public Content(String name,int num){
mName = name;
mNum = num;
}
@Override
public String toString() {
return "在"+mName+"家,有"+mNum+"只老鼠";
}
}
}
3、两个观察者对象。小花猫以及猫头鹰实现。
CatObserver .java
public class CatObserver implements Observer{
private String mName;
public CatObserver(String name){
mName = name;
}
public void registerSubjectObserver(Observable observable){
System.out.println("我是"+mName+",我注册成为了观察者,我要捉老鼠");
observable.registerObserver(this);
}
@Override
public void update(Observable o, Object obj) {
if(o instanceof Subject){
System.out.println(mName+"收到了通知:"+obj);
}else if(o instanceof DogObserver2){
System.out.println(mName+"接收到小狗共享的信息:"+obj);
}
}
}
Maotouying.java
public class Maotouying implements Observer{
private String mName;
public Maotouying(String name){
mName = name;
}
public void registerSubjectObserver(Observable observable){
System.out.println("我是"+mName+",我注册成为了观察者");
observable.registerObserver(this);
}
@Override
public void update(Observable o, Object obj) {
if(o instanceof Subject){
System.out.println(mName+"收到了通知:"+obj);
}
}
}
4、测试实现类:
public class ObserverTest {
public static void main(String args[]){
Subject subject = new Subject();
DogObserver dog = new DogObserver("小花狗");
CatObserver cat = new CatObserver("小花猫");
Maotouying owl = new Maotouying("猫头鹰");
//注册成为观察者,subject发现耗子,就会通知的
dog.registerSubjectObserver(subject);
cat.registerSubjectObserver(subject);
System.out.println("----------------------------------------");
System.out.println("发现老鼠,发出通知:");
subject.findMouse("小丽家", 3);
System.out.println("----------------------------------------");
System.out.println("【想让猫头鹰也接收到通知,很容易扩展实现】");
owl.registerSubjectObserver(subject);
System.out.println("----------------------------------------");
System.out.println("发现老鼠,发出通知:");
subject.findMouse("小张家", 9);
}
}
测试结果:
我是小花狗,我注册了成为了观察者,我要狗拿耗子
我是小花猫,我注册成为了观察者,我要捉老鼠
----------------------------------------
发现老鼠,发出通知:
小花狗收到了通知:在小丽家家,有3只老鼠
小花猫收到了通知:在小丽家家,有3只老鼠
----------------------------------------
想让猫头鹰也接收到通知,很容易扩展实现
我是猫头鹰,我注册成为了观察者
----------------------------------------
发现老鼠,发出通知:
小花狗收到了通知:在小张家家,有9只老鼠
小花猫收到了通知:在小张家家,有9只老鼠
猫头鹰收到了通知:在小张家家,有9只老鼠
总结:
在4中的测试程序中,我们可以看到2中的一个主题类,与3中的多个观察者对象那个产生了联系,定义了一对多的依赖。
当主题中的事件进行广播时,所有的观察者都收到了通知。主题类并不会关心观察者对象在收到广播时,是“去捉老鼠”,还是“狗拿耗子”。
5、扩展:猫头鹰意识到它喜欢的是田鼠,不是耗子,它决定不再接收通知。小花狗也意识到它在多管闲事,它决定将广播信息分享(观察者也可以成为主题,主题也可以成为观察者),比如打电话通知黑猫警长等。
DogObserver2.java
import java.util.ArrayList;
public class DogObserver2 implements Observable,Observer{
private ArrayList<Observer> mData = new ArrayList<Observer>();
private String mName;
private Object content;
private boolean checked = false;
public DogObserver2(String name) {
mName = name;
}
public void registerSubjectObserver(Observable observable){
System.out.println("我是"+mName+",我注册了成为了观察者,我要狗拿耗子");
observable.registerObserver(this);
}
@Override
public void registerObserver(Observer o) {
mData.add(o);
}
@Override
public void removeObserver(Observer o) {
mData.remove(o);
}
@Override
public void notifyObserver() {
for(Observer observer:mData){
observer.update(this, content);
}
}
@Override
public void update(Observable o, Object obj) {
content = obj;
if(checked){
System.out.println(mName+"不在狗拿耗子,分享耗子信息给他人");
notifyObserver();
}else{
System.out.println(mName+"收到了通知:"+obj);
}
}
public void setChecked(boolean check){
checked = check;
}
}
ObserverTest2.java
public class ObserverTest2 {
public static void main(String args[]){
Subject subject = new Subject();
CatObserver cat1 = new CatObserver("小花猫1号");
DogObserver2 dog = new DogObserver2("小花狗");
CatObserver cat2 = new CatObserver("小花猫2号");
CatObserver cat3 = new CatObserver("小花猫3号");
Maotouying owl = new Maotouying("猫头鹰");
cat1.registerSubjectObserver(subject);//花猫注册主题
owl.registerSubjectObserver(subject);//猫头鹰注册主题
dog.registerSubjectObserver(subject);//小狗注册主题
cat2.registerSubjectObserver(dog);//花猫2号,注册小狗主题,成为”小狗“的观察者
cat3.registerSubjectObserver(dog);
subject.findMouse("小赵", 8);
System.out.println("猫头鹰不想接收通知了");
subject.removeObserver(owl);
System.out.println("小狗决定不再多管闲事,分享耗子信息给他人");
dog.setChecked(true);
subject.findMouse("小王", 2);
}
}
测试结果:
我是小花猫1号,我注册成为了观察者,我要捉老鼠
我是猫头鹰,我注册成为了观察者
我是小花狗,我注册了成为了观察者,我要狗拿耗子
我是小花猫2号,我注册成为了观察者,我要捉老鼠
我是小花猫3号,我注册成为了观察者,我要捉老鼠
小花猫1号收到了通知:在小赵家,有8只老鼠
猫头鹰收到了通知:在小赵家,有8只老鼠
小花狗收到了通知:在小赵家,有8只老鼠
猫头鹰不想接收通知了
小狗决定不再多管闲事,分享耗子信息给他人
小花猫1号收到了通知:在小王家,有2只老鼠
小花狗不在狗拿耗子,分享耗子信息给他人
小花猫2号接收到小狗共享的信息:在小王家,有2只老鼠
小花猫3号接收到小狗共享的信息:在小王家,有2只老鼠