您的位置:首页 > 其它

观察者模式

2016-09-03 12:05 316 查看

观察者模式

观察者模式定义

   观察者模式(Observer Pattern)也叫做发布订阅模式(Publish/subscribe),他是一个在项目中经常使用的模式,其定义如下:

  Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically(定义对象间一种一对多的依赖关系,使得每一个对象改变状态,则所有依赖与它的对象都会得到通知和被自动更新)。

简单实现

   实现开发者模式我们首先举一个现实中的列子,大家上学的时候我们的老湿经常会给我们班级安排几个奸细(江湖传名“课代表”),让他们监视我们的动向,上课说话,打架,papapa这些奸细马上就会通知老湿,然后老湿就惩罚我们,好了这个就是一个观察者模式,以上讲到的这个场景有以下对象:

老湿-观察者(teacher)

学生-被观察者(student)包括奸细

首先创建学生(被观察者)的接口,定义学生的一些动作

package design.observier.observer000;
/**
* 学生接口
* @author yanwenfei
*
*/
public interface IStudent {
//学生上课的时候在说话
public void speakOnStudy();

//papapa
public void makeLove();
}


学生的实现类,把老湿安排课代表通过构造函数聚集到学生中,在学生活动的时候通过课代表调用update通知老湿

package design.observier.observer000;

//学生实现类
public class Student implements IStudent {

//聚集 一个奸细
private ITeacher teacher;

//老湿安排了一个心腹到学生里面
public Student(ITeacher teacher) {
this.teacher = teacher;
}

@Override
public void speakOnStudy() {
System.out.println("学生在学习的时候说话");
teacher.update("报告老湿:学生在学习的说话");
}
@Override
public void makeLove() {
System.out.println("学生在papapa");
teacher.update("报告老湿:学生在papapa");
}

}
老湿接口,老湿响应的方法

package design.observier.observer000;

/**
* 观察者
* @author yanwenfei
*
*/
public interface ITeacher {

//被通知后的操作
public void update(String str);
}


老湿的实现类,课代表告诉老湿后,打印了一句话

package design.observier.observer000;

public class Teacher implements ITeacher {

@Override
public void update(String str) {

System.out.println(str);
System.out.println("老湿知道了");
}

}


现在测试、

package design.observier.observer000;

public class TestMain {

public static void main(String[] args) {

ITeacher teacher = new Teacher();//创建一个老湿的课代表
Student stu = new Student(teacher);//创建一个学生,并把课代表放进去
stu.speakOnStudy();//学生在说话
stu.makeLove();//学生在papapa
}

}


运行结果:

学生在学习的时候说话
报告老湿:学生在学习的说话
老湿知道了
学生在papapa
报告老湿:学生在papapa
老湿知道了


以上为观察者模式最简单的实现,把观察着聚集到被观察者中,当被观察者有活动的时候,观察者马上执行一个方法,这就是观察者模式。

但是实际情况不是这样的,不可能只有一个老湿需要监视,可能还有语文课代表,英语课代表、数学课代表等等,以上简单的实现不能很好的扩展,如果需要增加一个课代表那要改很多代码,所有是有毒代码,下来看看下一节观察者模式扩展

观察者模式扩展

为了很好的扩展,增加观察者对象,就需要做以下修改:

增加 被观察者应该可以动态添加观察者
增加 被观察者应该可以动态删除观察者
增加 通知所有观察者
      考虑以下 以上这些操作,应该所有被观察者通用的方法,不应该在具体的被观察者中实现,所以应该创建一个抽象类来实现这些操作,具体的被观察者应该只实现自己的动作比如 啪啪啪,

代码清单应该是:

AbstractStudentOverser(抽象学生被观察者)实现添加删除观察者并通知

IStudent (学生接口)

StudentA (学生实现类)

ITeacherOberser(观察者接口)

Teacher(老湿实现类)

下来具体实现

package design.observier.observer001;
//观察者 可恶的老湿
public interface Teacher {
//老湿知道消息后惩罚被观察的学生
public void update(Object o);
}
王老湿:
package design.observier.observer001;

public class TeacherW implements Teacher {

@Override
public void update(Object o) {
System.out.println("王老湿:"+o.toString());
}

}


抽象的学生被观察者,创建一个动态数据存放所有的观察者,

package design.observier.observer001;

import java.util.ArrayList;
import java.util.List;

/**
* 抽象被观察的学生
* @author yanwenfei
*
*/
public abstract class AbStractStudent {

private final List<Teacher> teachers = new ArrayList<Teacher>();
//添加一个奸细
public void addSpy(Teacher t){
teachers.add(t);
};

//删除一个奸细
public void removeSpy(Teacher t){
teachers.remove(t);
};
//通知所有的奸细
public void notifyTeacher(Object o){
for (Teacher t:teachers){
t.update(o);
}
}
}

package design.observier.observer001;

public interface IStudent {
//学生上课的时候在说话
public void speakOnStudy();

//papapa
public void makeLove();
}

package design.observier.observer001;

public class StudentA extends AbStractStudent implements IStudent{

@Override
public void speakOnStudy() {
System.out.println("学生A:学习的时候在说话..");
this.notifyTeacher("奸细:报告老湿,学生A在学习的时候说话");
}

@Override
public void makeLove() {
System.out.println("学生A:在PAPAPA..");
this.notifyTeacher("奸细:报告老湿,学生A在AAA");
}

}

package design.observier.observer001;

public class TestMain {

public static void main(String[] args) {

StudentA stua = new StudentA();//学生A
Teacher teacherW = new TeacherW();
stua.addSpy(teacherW);
stua.makeLove();
stua.speakOnStudy();

StudentB stub = new StudentB();//学生B
stub.addSpy(teacherW);
stub.makeLove();
stub.speakOnStudy();

}

}


执行结果

学生A:在PAPAPA..
王老湿:奸细:报告老湿,学生A在AAA
学生A:学习的时候在说话..
王老湿:奸细:报告老湿,学生A在学习的时候说话
学生B:在PAPAPA..
王老湿:奸细:报告老湿,学生B在AAA
学生B:学习的时候在说话..
王老湿:奸细:报告老湿,学生B在学习的时候说话


通过这次扩展改造之后,代码的扩展性就很好,如果需要添加一个被观察者,只需要添加一个学生类接触抽象类实现接口就可以,如果需要添加观察者,只需要添加一个teacher类就可以,而不需要修改代码,符合了封闭原则

观察者优化

我这里讲的观察者优化,实际上是换汤不换药,因为JDK本身已经实现了观察者模式

java.util.Observable 被观察类
java.util.Observer  观察者


我们可以对以上代码作如下优化

IStudent 不用写了 没有变

学生A直接继承了JDK的Observer 而不需要自己创建

package design.observier.observer002;

import java.util.Observable;

public class StudentA extends Observable implements IStudent {

@Override
public void speakOnStudy() {
System.out.println("学生A:开始说话了..");
super.setChanged();
super.notifyObservers("奸细:报告老湿,学生A在说话");
}

@Override
public void makeLove() {
System.out.println("学生A:PAPAPA..");
super.setChanged();
super.notifyObservers("奸细:报告老湿,学生A在PAPAPA");
}

}
观察者老湿类也是继承了JDK的观察者类
package design.observier.observer002;

import java.util.Observable;
import java.util.Observer;

public class TeacherA extends Observable implements Observer {

@Override
public void update(Observable o, Object arg) {
System.out.println(arg.toString());
}

}

package design.observier.observer002;

public class TestMain {

public static void main(String[] args) {

StudentA a = new StudentA();
TeacherA bb = new TeacherA();
a.addObserver(bb);
a.makeLove();
}
}


执行结果:

学生A:在PAPAPA..
王老湿:奸细:报告老湿,学生A在AAA
学生A:学习的时候在说话..
王老湿:奸细:报告老湿,学生A在学习的时候说话
学生B:在PAPAPA..
王老湿:奸细:报告老湿,学生B在AAA
学生B:学习的时候在说话..
王老湿:奸细:报告老湿,学生B在学习的时候说话


结果是相同的,所以的JDK已经帮我们实现了很多设计模式和代码,所以学习对读源代码还是很有用的。

观察者模式优点

  观察者和被观察者之间的是抽象耦合(扩展性好)
  建立了一套触发机制

观察者模式缺点

   被观察者模式需要考虑运行的性能和效率,一个被观察着多个观察者,开发和调试就会比较复杂,而且在java中,消息通知是按照顺序执行的,如果一个观察者卡住,会影响所有的观察者。如果使用异步,那就更不好控制。

观察者模式应用场景

  跨系统的消息交换场景(消息对立的处理机制)
事件多级触发场景
关联行为场景

观察者模式注意事项

 广播链问题 (A 通知 B 通知 C通知D。。。。)

异步处理问题 (通知如果采用异步)
如果以上有问题,希望指出改正,谢谢

设计模式虽然不是一门技术,但是对我们平时编程与阅读API很有帮助,个人也只是皮毛重点还是应用,欢迎大神们加群一起探讨  群号:167014883
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  设计模式 观察者