Observer模式
意图:在对象之间定义一种一对多的依赖关系,这样当一个对象的状态改变时,所有依赖与它的对象都将得到通知并自动更新。
问题:当某个事件发生时,你需要向一系列对象发出通知,而这个对象的列表是不断变化的。
解决方案:Observer将监视某个事件的责任委托给一个中心对象:Subject。
参与者和协作者:Subject知道自己的Observer,因为Observer在Subject上注册自己。当关心的事件发生时,Subject必须通知Observer。Observer有责任在得到通知时从Subject处获取更多信息。
效果:如果某些Observer只对全部事件的一个子集感兴趣,那么Subject可能会告诉Observer它们不需要知道的事件。如果在Subject通知Observer之后,Observer又转过来请求附加信息,就可能需要额外的通信。
实现:
1.让“希望知道哦阿某个事件何时发生”的对象(Observer)将自己注册到另一个“监视事件发生或自己触发事件”的对象(Subject)上。
2.当事件发生时,Subject告诉Observer“你关心的事件已经发生了”。
3.为了能让所有的观察者型兑现实现Observer接口,有时候需要使用Adapter模式。
流程如下:
1.创建Concrete Subject,
2.Observer 注册到Subject中
3.改变Subject属性,Subject.Notify
4.Subject 告诉 Observer 自己被改变了,至于具体是那个数据改变了不用知道
5.Observer自己去Subject中取感兴趣的数据
在4.5步其实要注意一点就是为什么没有让Subject直接把Observer 感兴趣的数据给它,而是让Observer自己来取!
这其实就是对“责任”的一种处理,好的OOPL其实就是对责任的一种划分,
比如老师要通知学生上课,有两种方法
一。把学生具体的路径给它们,告诉它们要从那走,走多远,怎么转向...(选路径责任在老师)
二。老师告诉同学在那个教室上课,同学们自己来确定路线。(路径选择责任在学生)
很明显第二种方法简单实用的多,而且更灵活,想想如果多了一个同学,老师就要特地的为这个同学制定路线,无形中代码就多了
其实这有点类似于设计数据库,外键的方向一定要设计好一样!
在这种情况下可以假设当某一方的数量增加时,代码应该如何改,如果代码不断增加而且越来越不可控制,那就是一个错误的设计!
在这里我举一个项目中的例子
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* 这是项目里的一个例子
* 需求是实现一个聊天功能,比如用户名被改变,当远程的数据推送过来到UserDB后,UserDB要负责告诉每个列表来取数据更新
* @author blacklaw
*
*/
public class test {
public static void main(String[] args){
System.out.println("Go");
//创建实体和观察者
UserDB userDB = new UserDB();
FriendList friendL = new FriendList(userDB);
userDB.attach(friendL);
FriendList friendL2 = new FriendList(userDB);
userDB.attach(friendL2);
//修改数据
userDB.addUser("blacklaw");
//实体负责通知到对象
userDB.notifys();
}
}
//Concrete Subject
class UserDB{
Set<UserList> userLists = new HashSet<UserList>();
public String user;
//Observer Interface
interface UserList{
public void upadta();
}
public void addUser(String username){
user = username;
}
public void attach(UserList o){
userLists.add(o);
}
public void detach(UserList o){
userLists.remove(o);
}
public void notifys(){
Iterator it = userLists.iterator();
while(it.hasNext()){
((UserList)it.next()).upadta();
}
}
}
//Concrete Observer
class FriendList implements UserDB.UserList{
UserDB userDB;
FriendList(UserDB db){
userDB = db;
}
@Override
public void upadta() {
// TODO Auto-generated method stub
System.out.println("new user is " + userDB.user);
}
}