观察者模式

引入: 

观察者模式定义了一种一对多 的依赖关系,让多个观察者对象同时监视着被观察者的状态,当被观察者的状态发生变化 时, 会通知所有观察者, 并让其自动更新自己。

   在现实中有些对象数据发生了变化,则这些对象也需要发生变化。举个例子, 一个商家有一些产品,它和一些电商合作,每当有新产品时,就会把这 些产品推送到电商,现在只和淘宝、京东合作。

if (产品库有新产品) { 
推送产品到淘宝; 
推送产品到京东;
}

但如果电商多了,就需要添加更多的“推送产品到...”,这样复杂且耦合度高。

这是观察者模式就出场了。首先, 把每一个电商接口看成一个观察 者,每一个观察者都能观察到产品列表(被监听对象)。当公司发布新产品时,就会发送到 这个产品列表上, 于是产品列表(被监昕对象)就发生了变化,这时就可以触发各个电商 接口(观察者〉发送新产品到对应的合作电商那里。


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

import com.observer.Observer;
//被观察者列表清单
public class ProductList extends Observable{
	private List<String> productList = null;// 产品列表
	private static ProductList instance;// 类唯一实例

	private ProductList() {
	}// 构造方法私有化

	/**
	 * 取得唯一实例
	 * @return 产品列表唯一实例
	 */
	public static ProductList getInstance() {
		if (instance == null) {
			instance = new ProductList();
			instance.productList = new ArrayList<String>();

		}
		return instance;
	}
	/**
	 * 添加观察者(电商接口)
	 * @param observer  观察者
 	 */
	public void addProductListObserver(Observer observer){
		this.addProductListObserver(observer);
	}
	
	public void addProduct(String newProduct){
		productList.add(newProduct);
		System.out.println("产品列表新增了产品:"+newProduct);
		this.setChanged();//设置被观察对象发生变化
		this.notifyObservers(newProduct);//通知观察者,并传递新产品
		
	}

}

import java.util.Observable;
import java.util.Observer;
//京东电商接口
public class JingDongObserver implements Observer{

	@Override
	public void update(Observable o, Object product) {
		String newProduct=(String)product;
		System.out.println("发送新产品 "+newProduct+ " 同步到京东商城");
	}

}

//淘宝电商接口
....

public class Test {
	public static void main(String[] args) {
		ProductList observable = ProductList.getInstance();
		TaoBaoObserver taoBaoObserver = new TaoBaoObserver();
		JingDongObserver jingDongObserver = new JingDongObserver();
		observable.addObserver(taoBaoObserver);
		observable.addObserver(jingDongObserver);
		observable.addProduct("新增产品1");
	}

}

 

观察者模式

UML图:

代码实现:

/*
 * 观察者接口类IObserver
 */
public interface IObserver {
public void refresh(String data);
}
/*
 * 主题接口类ISubject
 */
public interface ISubject {
public void register(IObserver obs); //注册观察者

public void unregister(IObserver obs);//撤销观察者
public void notifyObservers(); //通知所有观察者

}
/*
 * 主题实现类Subject
 */
public class Subject implements ISubject {
	// 观察者维护向量
	private Vector<IObserver> vec = new Vector<>();
	private String data; // 主题中心数据

	public String getData() {
		return data;
	}

	public void setData(String data) {// 主题注册
		this.data = data;
	}

	@Override
	public void register(IObserver obs) {// 主题注册(添加)观察者
		vec.add(obs);
		// TODO Auto-generated method stub

	}

	@Override
	public void unregister(IObserver obs) {// 主题撤销(删除)观察者
		if (vec.contains(obs))
			vec.remove(obs);

	}

	@Override
	public void notifyObservers() {// 主题通知所有观察者进行数据响应
		for (int i = 0; i < vec.size(); i++) {
			IObserver obs = vec.get(i);
			obs.refresh(data);
		}
	}

}
/*
 * 一个具体观察者类 Observer
 */
public class Observer implements IObserver{

	@Override
	public void refresh(String data) {
		System.out.println("I have received the data: "+data);
		
	}

}
public class Test {
	public static void main(String[] args) {
		IObserver obs = new Observer();// 定义观察者对象
		Subject subject = new Subject();//定义主题对象
		subject.register(obs);//主题增加观察者
		subject.setData("Hello");//主题中心数据变动了
		subject.notifyObservers();//通知所有观察者进行数据响应
	}
}

 

 

深入观察者模式

(1)主题接口类ISubject和观察者接口类IObserver 可以改为泛型接口更通用。

(2)数据传递的两种方式“推”和“拉”

 推数据的方式是指主题对象直接将数据传送给观察者对象。(上面那种就是推)

而拉数据则是观察者对象可间接获得变化后的主题数据。

public interface IObserver<T> {
public void refresh(ISubject<T> obj);
}
public class Subject implements ISubject {
 ......
	@Override
	public void notifyObservers() {// 主题通知所有观察者进行数据响应
		for (int i = 0; i < vec.size(); i++) {
			IObserver obs = vec.get(i);
			obs.refresh(this);    //代替原来的obs.refresh(data);       
		}
	}
}

 

public class Observer implements IObserver{

	@Override
	public void refresh(ISubject obj) {
		Subject subject=(Subject)obj;
		System.out.println("I have received the data: "+data);
		
	}

}

(3)增加抽象层AbstractSubject

如果有很多个主题类,而每个主题类都要重写register(),unregister(),notifyObservers()方法。如果这三个方法的代码是相同的,那么在每个主题类中实现就让代码重复了,所以应该加个中间抽象层来解决这个问题。

 

jdk中的观察者设计模式

(其实第一个电商的例子中我们已经用到就是jdk中的观察者模式)

 

 public void notifyObservers(Object arg) {
     
        Object[] arrLocal;

        synchronized (this) {
        
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

1.通过jdk中notifyObservers()方法的实现,可以看出它设置了一个标识变量changed,只有当changed为true时,观察者对象才能数据响应(可想而知这样也才符合常理,没有数据变化就没有必要响应。)

2.void update(Observable o, Object arg) 和 public void notifyObservers(Object arg)  两个方法中增加了arg参数对象的设定,可以把一些比较信息由主题动态传递给观察者,让编程更加灵活。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值