观察者模式

观察者模式(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个被观察者相应多个观察者的依赖,这也是为什么观察者 = 公布者 + 订阅者。

当中抽象主题角色(Subject)的代码例如以下
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发生循环调用。


观察者模式的应用场景
  • 广播链问题。

    一个对象事实上既能够作为观察者也能够作为被观察者,这样消息像在广播链中传递。可是须要注意假设链的长度假设过程。就会变的复杂。难以控制。

  • 异步处理的问题。

    在异步处理过程须要考虑线程安全和队列的问题。








posted @ 2016-03-06 08:56  mengfanrong  阅读(276)  评论(0编辑  收藏  举报