您的位置:首页 > 其它

设计模式-观察者(一)

2016-05-27 17:43 225 查看

设计模式-观察者(一)

大家好,我们又见面了,还记得上次所写的 <<设计模式-策略模式>>么?,我们今天来学习另一个模式之前,先复习一下上次的”策略模式”是怎么定义的吧:

定义:

策略模式
定义
:算法族,分别封装起来,让他们之间可以互相替换,次模式让算法的变化独立于使用算法的客户.

“策略模式”中我们还学到了两个设计原则:

1 :找出应用中可能需要变化之处,把他们独立起来,不要和那些不需要变化的部分的代码混合在一起.

2 :针对借口编程,而不是针对实现编程.

思考……………

经过对”策略模式”的思考,是不是有点印象了? 下面我们继续向下一个模式进发把……..

这次我们先推出这个模式,名字为”观察者模式”, 它的
定义
: 观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新.

不懂?

当然,如果能现在就能明白其真谛的话,你可以关浏览器了,以后都不需要再来GC博客了……(开玩笑 ^_^)

我们一步一步来,先了解一下什么是观察者模式.

*不知道你订没订阅报纸(如果你从小到大没订阅过报纸或者书刊杂志,我只能说你错过了一个生活体验..) 好吧,瞎扯了,我们先介绍一下订阅报刊的过程:

假如你家附近有一所报社,而你又是<<意林>>(高中生应该都读过的)的爱好者,你当然会迫不及待的去订阅一年属于自己的<<意林>>.当你去报社订阅了<<意林>>之后,每当报社收到新出版的<<意林>>,它就会将你的那份送到你的家中供你阅读.*

好吧.整个流程应该弄明白了吧,是在不明白可以亲自去订阅一年的<<意林>>体验一把哈.

到这里,可能你会想:订阅报刊与”观察者模式”有什么关系啊~

我只能回答你:
其实订阅报刊整个流程就是"观察者模式"的整个流程
,也就是说
"订阅报刊"用了"观察者模式"
.

当然,如果你已经想到了,那么只能说你的智商真的是太高了(@_@)

报社就相当于”观察者模式”里的”发布者(publish)/主题(Subject)”,而你就相当于”观察者模式”里的”订阅者(Subscribe)/观察者(Observer)”

“观察者模式”介绍完毕~~~

骗你的,代码还没写,怎么可能介绍完毕呢.况且”观察者模式”有好多种,今天只介绍其一….

现在我们开始写代码吧…用代码来实现上面的”订阅报刊”的功能…

//定义报社类
public class NewspaperOffice  {

//定义主题后期会更新的数据
private int updatedata;

//通知所有的<<意林>>订阅者
@Override
public void notifyObservers() {
//订阅者1订阅了意林
Subscriber1 s1 = new Subscriber1();
//让订阅者1更新数据,也就是给订阅者1送去<<意林>>
s1.update(this.updatedata);

//订阅者2订阅了意林
Subscriber1 s2 = new Subscriber2();
//让订阅者2更新数据,也就是给订阅者2送去<<意林>>
s2.update(this.updatedata);
}

//当主题里的数据进行更新的时候,通知所有的观察者
public void setUpdatedata(int updatedata) {
this.updatedata = updatedata;
notifyObservers();
}

}

//定义订阅者1类
public class Subscriber1 {

//定义订阅者自己的信息
private String name;

//定义订阅者需要在报社那里接到的数据
private int updatedata;

//构造器里还装入了该订阅者的名字
public Subscriber1(String name){
this.name = name;
}

public void display() {
System.out.println("我是订阅者,我的名字叫: "+name+" , 这是从报社接到的数据: "+ updatedata);
}

public void update(int updatedata) {
this.updatedata = updatedata;
display();
}
}

//定义订阅者2类
public class Subscriber2 {

//定义订阅者自己的信息
private String name;
private int age;

//定义订阅者需要在报社那里接到的数据
private int updatedata;

//构造器里还装入了该订阅者的名字
public Subscriber1(String name, int age){
this.name = name;
}

//显示出信息
public void display() {
System.out.println("我是订阅者,我的名字叫: "+name+",  我的年龄是: "+age+" , 这是从报社接到的数据: "+ updatedata);
}

//更新订阅者手中的信息(也就是更新手中的<<意林>>书的个数)
public void update(int updatedata) {
this.updatedata = updatedata;
display();
}

}


看了上面的代码,你有没有一种想骂我的感觉,上面的代码太不灵活了,当然这不可能是”观察者模式”哈,我只是写了一个
java初学者
会设计的模式.

上面代码很不灵活,的确.如果有一天,又有一个”订阅者3”去报刊订阅<<意林>>,
NewspaperOffice
这个类就需要重新写代码,在
notifyObservers()
方法里添加”订阅者3”的实例…当有一天”订阅者2”不想订阅了,
NewspaperOffice
类又要重新重构代码.麻烦至极啊…

很显然啊,上面的代码太别没有遵循之间我们所说的两个设计原则,所有是一组极差,及其不具备灵活性的代码…

下面,我们用”观察者模式”编写上面的代码…

首先,我们需要
面向接口编程
,把
NewspaperOffice
Subscriber1
,
Subscriber2
提取一下.

/*
这里提供了一个Subject(主题)接口,接口里定义了:注册观察者方法,删除观察者方法,向已经注册的观察者发送消息的方法
*/

public interface Subject {
//用来注册观察者
public void registerObserver(Observer o);
//用来删除观察者
public void removeObserver(Observer o);
//通知所有已经注册的观察者
public void notifyObservers();
}

/*
定义Observer(观察者)接口,所有观察者都具备更新内部数据的功能
*/
public interface Observer {
//更新观察者内部的数据
public void update(int updatedata);
}

/*
定义Subscriber(订阅者)接口,所有订阅者都可以展出自己的内部信息(也就是所有订阅者都可以向别人展出手中意林数目
*/
public interface Subscriber {
//每一个订阅者都可以显示自己的信息
public void display();
}

/*
下面,我们的报社出厂了
*/
import java.util.ArrayList;
import java.util.List;

//报社对象实线了主题借口
public class NewspaperOffice implements Subject {

//定义主题后期会更新的数据
private int updatedata;

//建立一个list来装注册进来的观察者
private List <Observer>observers;

//构造函数,构造list
public NewspaperOffice(){
observers = new ArrayList<Observer>();
}
//添加注册观察者
@Override
public void registerObserver(Observer o) {
observers.add(o);
}

//移除观察者
@Override
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if(i >= 0){
observers.remove(i);
}
}

//通知所有的观察者
@Override
public void notifyObservers() {
for(Observer observer: observers){
observer.update(this.updatedata);
}
}

//当主题里的数据进行更新的时候,通知所有的观察者
public void setUpdatedata(int updatedata) {
this.updatedata = updatedata;
notifyObservers();
}

}

/*
定义订阅者1 实现了观察者接口,订阅者的接口

*/
public class Subscriber1 implements Observer, Subscriber {

//定义订阅者自己的信息
private String name;

//定义订阅者需要在报社那里接到的数据
private int updatedata;

//定义观察者引用
private Subject subject;

//构造器里接受到该观察者需要注册的到哪个主题。并且注册到该主题上
//构造器里还装入了该订阅者的名字
public Subscriber1(Subject subject, String name){
this.name = name;
this.subject = subject;
subject.registerObserver(this);
}

@Override
public void display() {
System.out.println("我是订阅者,我的名字叫: "+name+" , 这是从报社接到的数据: "+ updatedata);
}

@Override
public void update(int updatedata) {
this.updatedata = updatedata;
display();
}

}

/*
定义订阅者2,基本内容与订阅者1相似,但是请注意,订阅者1与订阅者2是完全不同的两个类型,因为订阅者2里需要填写年龄信息.
如果两个类一模一样,那写成一个类不就好了么?
为什么要这样设计两个类呢? 因为我们后期的订阅者是各种各样的,订阅者怎么变化都无所谓,这充分说明了我们类与类之间的耦合程度非常低.
*/
public class Subscriber2 implements Observer, Subscriber {

//定义订阅者自己的信息
private String name;
private int age;

//定义订阅者需要在报社那里接到的数据
private int updatedata;

//定义观察者引用
private Subject subject;

//构造器里接受到该观察者需要注册的到哪个主题。并且注册到该主题上
//构造器里还装入了该订阅者的名字
public Subscriber2(Subject subject, String name, int age){
this.age = age;
this.name = name;
this.subject = subject;
subject.registerObserver(this);
}

@Override
public void display() {
System.out.println("我是订阅者,我的名字叫: "+name+",  我的年龄是: "+age+" , 这是从报社接到的数据: "+ updatedata);
}

@Override
public void update(int updatedata) {
this.updatedata = updatedata;
display();
}

}


基本结构都已经设计完了,现在我来写个测试类进行测试

public class Main {
public static void main(String[] args) {
//创建报社
NewspaperOffice nsp1 = new NewspaperOffice();

//用Subscriber1创建订阅者1,并且将他注册到报社
Subscriber1 GC = new Subscriber1(nsp1, "GC");
//用Subscriber2创建订阅者2,也注册到报社
Subscriber2 YP = new Subscriber2(nsp1, "YP", 33);

System.out.println("===========下面开始发布第1版报纸,此时GC与YP都在报社里========");
//现在报社开始发布第一版报纸
nsp1.setUpdatedata(1);
System.out.println("===========下面开始发布第2版报纸,此时GC与YP都在报社里========");
//报社发布第二版报纸
nsp1.setUpdatedata(2);

//现在GC不订阅报纸了,报社删除GC
nsp1.removeObserver(GC);
System.out.println("===========下面开始发布第3版报纸,此时只有YP都在报社里========");
//删除GC之后,报社又发布了第三版报纸
nsp1.setUpdatedata(3);

/*
* 运行结果如下:
* ===========下面开始发布第1版报纸,此时GC与YP都在报社里========
* 我是订阅者,我的名字叫: GC , 这是从报社接到的数据: 1
* 我是订阅者,我的名字叫: YP,  我的年龄是: 33 , 这是从报社接到的数据: 1
* ===========下面开始发布第2版报纸,此时GC与YP都在报社里========
* 我是订阅者,我的名字叫: GC , 这是从报社接到的数据: 2
* 我是订阅者,我的名字叫: YP,  我的年龄是: 33 , 这是从报社接到的数据: 2
* ===========下面开始发布第3版报纸,此时只有YP都在报社里========
* 我是订阅者,我的名字叫: YP,  我的年龄是: 33 , 这是从报社接到的数据: 3
*/

}
}


这是“观察者”模式的类图,里面只有Subject类与Observer类之间的关系,请仔细思考。



好吧,我承认,”观察者模式”不是那么容易理解,如果你看了我上面所写的内容之后就的能理解”观察者模式”,我真的再次赞叹一下:你的智商真的很高很高….

经过对将近两个小时的奋斗,终于把<<设计模式-观察者模式>>写完了,如果有不会的,没看懂的请
Email
或者
留言
给我……………

请转发OR复制的同学,
标注出处
,
尊重作者劳动成果
,谢谢亲

谢谢观看,结束本节!

注:本文借鉴了《HeadFirst-设计模式》一书,作者总结的内容不到书内容精彩十分之一,还望大家多读原著。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: