第四篇:观察者模式

今天我们来谈谈观察者模式,这个模式其实无论是在编程还是在生活中都是随处可见的,就比如说,你在烧一壶水,某个时间段后,当水壶“叮”的一声,你知道水开了,这个时候,你可能会去拔掉电源插头,可能会去拿起水壶泡一壶茶;当然这一切到底做不做都取决于你,水壶已经履行了它的义务,“将水烧开再叮的一声通知你...”

又比如说,你在优酷订阅了某个有趣的节目,当节目有更新时,你会收到通知,当然,还有其它订阅了该频道的用户也会收到通知...等等等等,那么我们通过这两个列子来看看,观察者模式它是怎么定义的呢?它有些什么样的角色呢?让我们画个图来更直观的了解下吧!

画图之前,我们先说,观察者模式有哪些角色和定义 ; 

1:观察者 ; 2:被观察者;3:事件触发;4:事件通知


我们先来将烧水这个例子画个图看看!


在这个图中,你在观察着水壶,而水壶将水烧开后,发出叮的一声告诉你水开了,你应该做些什么了! (注:面向对象中,我们可以将叮的一声看成一个行为,也就是一个方法)

那么,这里面的几个角色和动作,我们可以定义为:

你 ===== 观察者;水壶 ===== 被观察者;水开了 ===== 事件触发;叮的一声 ===== 事件通知


这个例子有点抽象,让我们来看一个更具体的吧!

我们用第二个例子来画图!


我们先看看如果不用观察者模式,代码可能会是什么样子...

/**某个节目*/
class Broadcast {
	//节目组名称
	private String name ; 
	//发布节目内容
	private String content;
	
	public String getName() {return name;}
	public void setName(String name) {this.name = name;}
	public String getContent() {return content;}
	public void setContent(String content) {this.content = content;}
	
}

/**用户*/
class User {
	
	/**更新用户的通知栏显示内容方法
	 * @param content 通知内容
	 * */
	public void notifyBar(String content){
		System.out.println("收到通知:"+content);
	}
}


/**栏目发布中心*/
public class PublishController {
	/**发布节目*/
	public void publish(Broadcast broadcast){
		System.out.println("节目发布!");
		//我们假设就只有一个用户,给用户发通知
		User user = new User();
		user.notifyBar("您关注的\""+broadcast.getName()+"\"发布了新的节目:"+broadcast.getContent());
	}
}

public class Test {
	public static void main(String[] args) {
		Broadcast broadcast = new Broadcast();
		broadcast.setName("社会百态");
		broadcast.setContent("论未成年人的保护重要性");
		PublishController pc = new PublishController();
		pc.publish(broadcast);
	}
}

输出结果:

**************************************************************************************

节目发布!
收到通知:您关注的"社会百态"发布了新的节目:论未成年人的保护重要性
**************************************************************************************

让我们接着看随着需求的变化,代码可能要发生怎样的改变...

/**栏目发布中心*/
public class PublishController {
	/**发布节目*/
	public void publish(Broadcast broadcast){
		System.out.println("节目发布!");
		//我们假设就只有一个用户,给用户发通知
		User user = new User();
		user.notifyBar("您关注的\""+broadcast.getName()+"\"发布了新的节目:"+broadcast.getContent());
		
		//随着产品影响力的扩大和用户反馈,需求的迭代导致功能修改不可避免的发生,无论怎样,我们都得继续改动这个方法的代码
		//需求1:某些质量比较好的节目,一旦发布就得推送到网站首页,好,咱们加代码!
		Website ws = new Website();
		ws.checkQuality(broadcast.getContent());
		
		//需求2:每发布一次节目,节目制作方可获得100点积分...
		//XXX xx = new Xxx();
		//xx.xxx();
		
		//需求3:每发布一次节目,节目制作方将获得一笔鼓励费用...
		//需求4...以后可能还有各种各样的需求...
	}
}

是的,我们看到了随着需求的变化对PublishController类带来的变化,看到了它的设计存在着众多的问题;

1:面向对象设计原则,多扩展开发,对修改关闭,很显然,它完全违背了这个思想,每次扩展功能都要修改既有代码,导致测试同童鞋每次都需要将全部功能测试一遍!;

2:与各种类严重耦合,我们说过,要依赖与抽象不依赖实现,这是对为今后能扩展功能的最基本的要求;

3:违背面向对象单一职责原则,它不应该知道具体如何去通知用户,如何去更新积分,如何去更新网站首页...更好的做法是,它只负责对某个抽象类发送一个通知,并告诉它们更新了什么东西,至于你接下来要做什么,我可不管!


好吧,不多说,我们马上来将上面的代码改造成观察者模式!

增加观察者和被观察者接口:

/**表示某个类具备观察的能力 (也可以称这个类为监听对象)*/
public interface Observer {
	
	/**被观察者对观察者的事件通知方法,也可以称之为回调方法*/
	void update(Broadcast broadcast);
}

/**表示某个对象具备被观察的能力*/
public interface Observerable {
	
	/**注册一个观察者*/
	void registryObserver(Observer observer);
	
	/**移除一个观察者*/
	void removeObserver(Observer observer);
	
	/**通知所有观察者*/
	void notifyAllObserver(Broadcast broadcast);
}

对user和Website的改动:

/**用户*/
class User implements Observer{
	//保存被观察者的引用,这样一来,后期我可以自己决定是否要取消关注
	private Observerable observerable;
	
	public User( Observerable observerable ) {
		this.observerable = observerable;
		//添加对被观察者的监听
		observerable.registryObserver(this);
	}
	/**更新用户的通知栏显示内容方法
	 * @param content 通知内容
	 * */
	public void notifyBar(String content){
		System.out.println("收到通知:"+content);
	}
	
	/**增加回调方法*/
	@Override
	public void update(Broadcast broadcast) {
		notifyBar(broadcast.getContent());
	}
}

/**表示整个站点*/
class Website implements Observer{
	//保存被观察者的引用,这样一来,后期我可以自己决定是否要取消关注
	private Observerable observerable;
	
	public Website( Observerable observerable ) {
		this.observerable = observerable;
		//添加对被观察者的监听
		observerable.registryObserver(this);
	}
	public void checkQuality(String content){
		System.out.println("节目内容检查通过,被鉴定为优质节目...");
		System.out.println("站点某个位置数据更新为:"+content);
	}
	
	/**增加回调方法*/
	@Override
	public void update(Broadcast broadcast) {
		checkQuality(broadcast.getContent());
	}
}
对PublishController的改动:
/**栏目发布中心*/
public class PublishController implements Observerable{
	
	//增加一个集合用于维护所有的观察者
	List<Observer> observers ;
	public PublishController() {
		observers = new ArrayList<>();
	}
	
	/**发布节目*/
	public void publish(Broadcast broadcast){
		System.out.println("节目发布!");
		notifyAllObserver(broadcast);
	}

	@Override
	public void registryObserver(Observer observer) {
		observers.add(observer);
	}

	@Override
	public void removeObserver(Observer observer) {
		int index = observers.indexOf(observer);
		if(index!=-1){
			observers.remove(index);
		}
	}
	
	/**通知所有观察者*/
	@Override
	public void notifyAllObserver(Broadcast broadcast) {
		for (Observer observer : observers) {
			observer.update(broadcast);
		}
	}
}

测试一下:

public class Test {
	public static void main(String[] args) {
		Broadcast broadcast = new Broadcast();
		broadcast.setName("社会百态");
		broadcast.setContent("论未成年人的保护重要性");
		
		PublishController pc = new PublishController();
		//可以随意增加监听用户了!
		User user = new User(pc);
		User user2 = new User(pc);
		User user3 = new User(pc);
		Website ws = new Website(pc);
		pc.publish(broadcast);
		
		//需求改动,说:不再需要更新站点...简单,我们只需要移除站点监听对象就OK啦!
		pc.removeObserver(ws);
		System.out.println("*******************************************");
		pc.publish(broadcast);
		
		//需求改动,说:要增加一个新的功能...
		//简单,我们只需要这样做
		//Observer xxx = new xxx();
		//pc.registryObserver(xxx);
	}
}


内容输出:

****************************************************************************

节目发布!
收到通知:论未成年人的保护重要性
收到通知:论未成年人的保护重要性
收到通知:论未成年人的保护重要性
节目内容检查通过,被鉴定为优质节目...
站点某个位置数据更新为:论未成年人的保护重要性
*******************************************
节目发布!
收到通知:论未成年人的保护重要性
收到通知:论未成年人的保护重要性
收到通知:论未成年人的保护重要性
****************************************************************************

这样一来,后面我们需要扩展功能,只需要增加一个监听对象,而要取消某个功能,只需要移除监听就可以啦!再看我们的PublishController类,无论对于以后的功能扩展和取消都完全不需要改变了!而且与具体的实体类,比如User,Website解耦了!在它世界里,耦合的对象只剩下Observer接口;

最后,让我们对观察者模式来下一个定义:

观察者模式:在对象与对象之间建立一对多的关系,当被监听的对象某些状态发生改变或者某个行为被触发,监听它的多的一方将自动收到通知并采取更新动作!

java也提供了Observer和Observable;只不过它的Observable是个类,你需要去继承,而我们的是个接口,可以更灵活的实现 ”多继承“!


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值