这次我来回顾观察者模式的实现与在实际项目中使用结合时需要考虑以及设计的一些状况
首先是什么是观察者模式,它的功能是什么
打个比方, 有一块地皮,有很多家开发商都想将它买下来,但是,他们需要等待这块地皮的开卖信息,当有最新信息的时候,就要立刻让各个开发商知道,那么这种时候就可以用到观察者模式
第一步,首先我们需要定好接口,我在这里定义了两个接口
第一个接口是中介接口,他负责提供土地价格变更时的通知服务
/**
* 土地价格中介,接受土地价格监视的委托
* 在土地价格变更时通知订了服务的人
* @author yjh
*
*/
public interface LandPriceIntermediary {
/**
* 开通土地价格变更通知服务
* @param observer
*/
public void registLandPriceChangeNotice(Observer observer);
/**
* 注销土地价格变更服务
* @param observer
*/
public void removeLandPriceChangeNotice(Observer observer);
/**
* 进行价格变更通知
*/
public void noticeLandPriceChange();
}
第二个是被通知者的接口,他主要用于被通知,希望被土地价格变更时通知的类都需要实现
/**
* 被通知者
* @author Administrator
*
*/
public interface Observer{
public void update(int price);
}
在接口定义好了之后,就可以开始实现了,首先我们需要一个实体的中介
/**
* 土地的信息中介
* @author Administrator
*
*/
public class LandInfoIntermediary implements LandPriceIntermediary{
private ArrayList<Observer> mObservers = new ArrayList<Observer>();
private float mPrice;//价格
private float mArea;//面积
@Override
public void registLandPriceChangeNotice(Observer observer) {
mObservers.add(observer);
}
@Override
public void removeLandPriceChangeNotice(Observer observer) {
mObservers.remove(observer);
}
@Override
public void noticeLandPriceChange() {
for(Observer observer:mObservers){
observer.update(mPrice,mArea);
}
}
/**
* 发布中心的价格改变了
* @param price
* @param area
*/
public void changeLandInfo(float price,float area){
mPrice = price;
mArea = area;
noticeLandPriceChange();
}
}
然后需要一个订阅了土地信息的用户
/**
* 尚德房产公司
* @author Administrator
*
*/
public class ShangDeHousePropertyCompany implements Observer{
/**
* 在构造器内进行监听注册
* @param intermediary
*/
public ShangDeHousePropertyCompany(LandPriceIntermediary intermediary){
intermediary.registLandPriceChangeNotice(this);
}
@Override
public void update(float price, float area) {
infoReply(price, area);
}
/**
* 将信息变更进行处理
* @param price
* @param area
*/
private void infoReply(float price, float area){
//处理
}
}
这样,在运行时,只要价格变更了,尚德房产公司就会立刻收到价格以及面积改变的信息,立刻进行处理
到这里,就是观察者模式的基本实现方式
接下来联系我们实际的项目中的需求来思考观察者模式的实现
我从聊天类软件开始需求,在这里,我们要模拟的就是聊天软件的信息通知中心
需求一:多处需要在同时收到通知的时候,需要的是不同的数据,而这些数据又不方便放在同一个对象中时
举例,我们有一个信息接收中心,然后有两个观察者
1、负责在收到信息之后,在通知栏粗略显示一边收到的信息
2、负责在收到信息之后,显示未读信息的数量
这两个都是在收到信息之后需要被通知然后做不同处理的,但是他们所需要的数据是不同的,一个是信息内容
一个是未读信息数量,那么这个时候我们应该如何处理?
经过思考之后,我想到了一个方法
/**
* 信息中介
* @author Administrator
*
*/
public interface MessageIntermediary {
public void registServe(Observer observer);
public void calcelServe(Observer observer);
public void noticeObserve();
/**
* 获取收到的信息本体
* @return
*/
public MessageNotice getCurrentMessageNotice();
/**
* 获取未读信息数量
* @return
*/
public int getUnReadCount();
/**
* 被通知者
* @author Administrator
*
*/
public interface Observer{
public void update(MessageNotice notice);
}
/**
* 收到的信息本体,这里只考虑简单的情况
* @author Administrator
*
*/
public class MessageNotice{
private String mFromUserId;//信息来源
private String mMessageType;//信息类型,单聊、群聊
private String mMessage;//信息本体,这里只模拟收到文字信息的情况
}
}
其实实现的方式有很多, 但是这边这种却扩展了一种思路,原本在通知收到之后所有的信息都是中介推给订阅者,而这里则是订阅者 自己从中介拉过来的,是一种更加有针对性的获取,只来获取自己需要的信息
这种拉的方式,可以满足每个被通知者不同的数据需求,同时,如果原本的某一个被通知者扩展了需要被通知的数据,这种方式也可以很好的兼容,而原来的方式则会导致改动起来很麻烦
需求二:有多种通知,而不同监视者需要监视不同的信息通知,不同监视者只会对特定分类的信息有反应
这里的话,我想了一下,有两种方式:
1、一种在注册监视的时候就通过多传参数来指定自己所需监听信息的类型,在通知时根据类型通知
这种方式的确可以满足需求,然而,当与拉的方式结合,并且接受的信息种类很多时,会导致代码可读性变差,管理起来也很麻烦
2、写成多个信息被监视中心,分别通知管理
这种方式适用于不同信息的通知是通过不同方式通知的时候,如果只有一个接受中心的话,看方式3
3、被监视者本身也可以是监视者,为每一个类型的数据写一个被监视中心,然后所有的被监视中心共同监视总的数据接受中心。
这样监视者在注册时也比较方便,数据也比较方便管理,只是这种情况只在服务器端的通知机制比较不友好,所有类型的信息都只通过一个数据接受处接受比较适用,否则还是写成多个被监视中心比较好(之前公司的项目就是这样不友好。。。)