设计模式--观察者模式

当一个对象的某个状态改变时,随之而来的是改变其他对象的状态。比如商品降价时,要通知所有关注此商品的人,我们可能第一时间想到这样写:

/**
 * @ClassName: Commodity
 * @Description: 商品类
 */
public class Commodity {
	//商品价格
	private Double price;
	
	public void priceChanged(){
		BuyerOne buyerOne = new BuyerOne();
		//通知第一位买家价格变动
		buyerOne.getNewPrice(price);
		
		BuyerTwo buyerTwo = new BuyerTwo();
		//通知第二位买家价格变动
		buyerTwo.getNewPrice(price);
	}
}

这样写有以下几个缺点:

1.    针对具体实现编程,而非针对接口编程

2.    每一次有增加或减少通知对象,我们都要修改代码;

3.    我们没办法在程序运行时,动态地增加或减少需要通知的对象,没有弹性;

4.    严重侵犯了通知对象的封装。

为了解决避免上述缺点,采用观察者模式解决这一类问题。观察者模式(Observer Parttern),对象之间存在一对多的依赖,当一个对象的状态发生改变时,它所依赖的对象都会得到通知并随之改变,这个对象我们称之为主题(Subject),它所依赖的对象我们称之为观察者(Observer)。

主题对象管理者某些数据,当主题数据发生了改变时会通知它的观察者,观察者已经订阅了主题数据发生改变时,这些观察者也会得到改变信息,做出相应的反应。相反,不是该主题的观察者,无论主题数据如何变化,这个对象始终都接受不到消息更不会因为主题对象的改变而改变。

在上述例子中,两个买家对象都实现了同样的getNewPrice()方法,采用具体实现完成这项工作,耦合度很高。一个系统的耦合度较高时,那么这个系统的弹性就会很差,很难应付频发的业务变化。观察者模式提供了一种对象设计,将主题与观察者之间松耦合,通过针对接口来代替具体实现,主题中只要知道观察者实现了某个接口,而所有的观察者都实现这个接口,具体的实现大家互补侵犯。因为观察者实现了统一的接口,主题存储这个接口列表就可以实现在程序运行时,动态的增加或删除注册的观察者。

有了大概思路,接下来看如何将上面的例子使用观察者模式实现:

买家接口,也就是观察者接口:

/**
 * @ClassName: Buyer
 * @Description: 买家接口
 */
public interface Buyer {
	/**
	 * @Title: getNewPrice
	 * @Description: 得到新的价格
	 * @param price
	 */
	public void getNewPrice(Double price);
}

商品类,也就是主题:

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: Commodity
 * @Description: 商品类
 */
public class Commodity {
	
	//商品价格
	private Double price;
	
	//用来记录所有的买家(观察者列表)
	private List<Buyer> buyers;
	
	//在基础构造方法中初始化记录买家的列表
	public Commodity(){
		this.buyers = new ArrayList<Buyer>();
	}
	
	//买家注册,其实就是将买家变成观察者,加入到观察者列表
	public void registerBuyer(Buyer buyer){
		this.buyers.add(buyer);
	}
	
	//当买家不在关注此商品是,取消订阅,从观察者列表中将其删除
	public void removeBuyer(Buyer buyer){
		int i = this.buyers.indexOf(buyer);
		if(i >= 0){
			this.buyers.remove(i);
		}
	}
	
	//价格状态改变,通知所有买家
	//向所有订阅者发送状态改变消息
	private void priceChanged(){
		for(Buyer buyer : buyers){
			buyer.getNewPrice(this.price);
		}
	}
	
	//模拟打折活动,当调用打折方法,修改了价格,
	//也就意味着主题状态改变,应该执行通知所有观察者
	public void discountCommodity(Double price){
		//第一步,修改价格
		this.price = price;
		//第二部,通知所有观察者
		priceChanged();
	}
}

具体的买家,也就是具体的观察者,实现观察者接口的实现类:

/**
 * @ClassName: BuyerOne
 * @Description: 买家1
 */
class BuyerOne implements Buyer{
	//商品价格
	private Double price;
	
	@Override
	public void getNewPrice(Double price) {
		this.price = price;
		System.out.println("BuyerOne get new price : " + price);
	}
}

/**
 * @ClassName: BuyerTwo
 * @Description: 买家2
 */
class BuyerTwo implements Buyer{
	//商品价格
	private Double price;
		
	@Override
	public void getNewPrice(Double price) {
		this.price = price;
		System.out.println("BuyerTwo get new price : " + price);
	}
}

执行测试:

public class Test {
	//进行测试
	public static void main(String[] args){
		
		//创建商品
		Commodity commodity = new Commodity();
		
		//第一个买家进行关注,也就是说第一个观察者进行了注册
		BuyerOne one = new BuyerOne();
		commodity.registerBuyer(one);
		
		//第二个注册
		BuyerTwo two = new BuyerTwo();
		commodity.registerBuyer(two);
		
		//执行降价操作,所有观察者都应该受到信息
		commodity.discountCommodity(0.2);
	}
}

以下就是执行结果:

BuyerOne get new price : 0.2

BuyerTwo get new price : 0.2

由此可以看到主题发生了状态改变,达到了通知所有观察者的效果。观察者模式的简单实现就此完成。

总结:

1、观察者模式就是对象直接存在一对多的依赖,一的一方(主题)改变,要通知多的一方(观察者)

2、面向接口编程,不是面向类编程,减少代码入侵

3、程序运行时,可动态修改主题状态

4、让主题和观察者之间松耦合,弹性更好

下面一篇将介绍Java内置的观察者模式,并进行源码分析。


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值