观察者模式
观察者模式(Observer Pattern)在项目中常常会被使用到。也被叫做公布订阅模式,也就是说 观察者 = 公布者 + 订阅者
GoF的《设计模式》中对观察者是这样描写叙述的:
Define a one-to-many dependency between objects so that when one object changes state。 all its dependents are notified and updated automatically。
意思就是。定义一个对象之间的一对多的依赖关系,使得当一个对象的状态发生改变的时候,它的全部依赖对象可以自己主动地被通知以及被更新。这里须要注意原句被动语态的使用。依赖对象不是主动检測。而是被通知和被更新。
观察者模式的UML
能够发现,观察者模式共涉及4种角色:
抽象主题角色(Subject):也就是被观察者角色,它能够在自己的内部加入或删除一个观察者对象,这些观察者对象将作为它的通知对象。
抽象观察者角色(Observer):为全部的观察者对象定义一个共同的接口,指定同样的通知规范。
详细主题角色(Concrete Subject):实现抽象主题角色,是详细真实的被观察者。
详细观察者角色(Concrete Observer):实现抽象观察者角色,是详细真实的观察者。一般有多个,能够定义自己收到被观察者通知后运行的业务逻辑。
事实上再抽象一点划分。观察者模式仅仅有两个角色:观察者和被观察者。也就是1个被观察者相应多个观察者的依赖,这也是为什么观察者 = 公布者 + 订阅者。
public interface Subject {
//注冊观察者对象o
public void attach(Observer o);
//删除观察者对象o
public void detach(Observer o);
//通知观察者
public void notifyObserver();
}抽象主题角色(被观察者角色)定义了添加和删除观察者的方法,详细的被观察者须要维护一个观察者列表,当被观察者的状态发生变化的时候,回去主动的通知列表中的观察者。
抽象观察者角色(Observer)的代码实现:
public interface Observer {
//接收到通知的操作
public void update();
}仅仅有一个update方法,用于接收到来之被观察者通知的时候採取的更新操作,这种方法一般由被观察者调用。
以下是这两个接口的详细实现,也就是详细主题角色(详细被观察者角色)、详细观察者角色
import java.util.LinkedList;
import java.util.List;
public class ConcreteSubject implements Subject {
//用于保存自己的注冊对象
private List<Observer> observerList = new LinkedList<Observer>(); //方便常常的插入和删除操作
/**
* 注冊一个观察者
*/
@Override
public void attach(Observer o) {
// TODO Auto-generated method stub
observerList.add(o);
}
/**
* 取消一个观察者
*/
@Override
public void detach(Observer o) {
// TODO Auto-generated method stub
observerList.remove(o);
}
/**
* 通知观察者
*/
@Override
public void notifyObserver() {
// TODO Auto-generated method stub
for(Observer obs : observerList ) {
obs.update(); //逐个通知观察者
}
}
}
public class ConcreteObserver implements Observer {
/**
* 接到通知的逻辑
*/
@Override
public void update() {
// TODO Auto-generated method stub
}
}观察者模式的详细实例
一个典型的样例就是消息订阅,比方,我们在关注了一个某晚报微信公众号,然后每天公众号给我们发送订阅的新闻,这里公众号就是一个被观察者角色,而我们订阅者就是观察者角色
抽象主题角色Subject,也就是公众号的简单抽象定义:
public interface PublicOffcial {
//注冊订阅消息的用户
public void attach(WechatUser user);
//取消订阅消息的用户
public void detach(WechatUser user);
//向用户发送订阅
public void notifyObserver(String news);
}抽象观察者角色,这里也就是微信订阅用户的简单抽象
public interface WechatUser {
public void readNews(String news);
}实现详细主题角色(真实被观察者),这里是XX晚报的公众号
import java.util.LinkedList;
import java.util.List;
public class PublicOffcialXXNewPaper implements PublicOffcial {
//已订阅用户的列表
private List< WechatUser> list = new LinkedList<WechatUser>();
/**
* 当用户订阅时。增加列表
*/
@Override
public void attach(WechatUser user) {
if( ! list.contains(user))
list.add(user);
}
/**
* 用户取消订阅时,从列表清除
*/
@Override
public void detach(WechatUser user) {
if(list.contains(user))
list.remove(user);
}
/**
* 通知订阅者
*/
@Override
public void notifyObserver(String news) {
for(WechatUser user : list ) {
user.readNews(news);
}
}
/**
* 报社某天的公布新闻工作,包含发送给微信订阅者,可能还要更新站点
* @param news
*/
public void ReleaseNews(String news) {
//something to do e.g: update website..
System.out.println("报社公布今日新闻【" + news + "】");
notifyObserver(news);
}
}
详细观察者角色,也就是订阅消息的用户
public class NewsPaperFan implements WechatUser {
private String name;
public NewsPaperFan(String name) {
// TODO Auto-generated constructor stub
this.name = name;
}
@Override
public void readNews(String news) {
System.out.println("用户: " + name + "收到订阅的新闻【" + news + "】");
}
}以上就是关于消息订阅的观察者模式的实现。
client測试类:
public class Client {
public static void main(String[] args) {
PublicOffcialXXNewPaper newPaper = new PublicOffcialXXNewPaper();
WechatUser user1 = new NewsPaperFan("Tony");
WechatUser user2 = new NewsPaperFan("Jack");
WechatUser user3 = new NewsPaperFan("David");
newPaper.attach(user1);
newPaper.attach(user2);
newPaper.attach(user3);
newPaper.ReleaseNews("苹果即将推出IPhone6...");
}
}
程序输出:
报社公布今日新闻【苹果即将推出IPhone6...】 用户: Tony收到订阅的新闻【苹果即将推出IPhone6...】 用户: Jack收到订阅的新闻【苹果即将推出IPhone6...】 用户: David收到订阅的新闻【苹果即将推出IPhone6...】
综上,能够看出观察者模式的一些长处:
- 观察者和被观察者之间是抽象耦合的。
被观察者仅仅能观察到观察者的接口层定义。而不知道自己通知的观察者的详细类型,它们之间属于不同的抽象层面,没有紧密的耦合,easy扩展。
- 支持像消息订阅这种广播通信。
一些缺点:
- 假设被观察者须要通知多个观察者,或者通知过程时候耗时,那么上述被观察者的通知过程将会很耗时。
对于这一点。假设通知的过程是相互独立的任务。那么能够使用多线程去完毕,使通知在子线程中完毕。
- 假设拥有多个被观察者。而且它们之间存在依赖关系,那么easy发生循环调用。
观察者模式的应用场景
- 广播链问题。
一个对象事实上既能够作为观察者也能够作为被观察者,这样消息像在广播链中传递。可是须要注意假设链的长度假设过程。就会变的复杂。难以控制。
- 异步处理的问题。
在异步处理过程须要考虑线程安全和队列的问题。
浙公网安备 33010602011771号