Java设计模式(17)——行为模式之观察者模式(Observer)
一、概述
概念
UML简图
我们根据一个示例得类图来分析角色
角色
抽象主题:保存观察者聚集(集合),管理(增删)观察者
抽象观察者:定义具体观察者的抽象接口,在得到主题通知后更新自己
具体主题:将有关状态存入具体观察者,状态发生改变时,通知观察者
具体观察者:存储与主题角色自洽的状态
二、实践
我们先将上面的示例图使用Java代码实现,再讨论Java中的观察者
抽象主题
/**
* 抽象主题接口
*
* @author Administrator
**/
public interface Subject {
/**
* 登记/增加一个观察者
* @param observer 新增的观察者
*/
void attach(Observer observer);
/**
*删除一个观察者
* @param observer 删除的观察者
*/
void detach(Observer observer);
/**
* 通知观察者
*/
void notifyObserver();
}
具体主题——可以注意复习我们之前学习的拉姆达表达式
/**
* 具体主题角色
*
* @author Administrator
**/
public class ConcreteSubject implements Subject{
private List<Observer> observerList = new LinkedList<>();
@Override
public void attach(Observer observer) {
observerList.add(observer);
}
@Override
public void detach(Observer observer) {
observerList.remove(observer);
}
@Override
public void notifyObserver() {
// 遍历通知观察者(可以使用聚集的拷贝防止外部的修改)
for (Observer observer : observerList) {
observer.update();
}
// Java8写法
// observerList.forEach((observer)-> observer.update());
// observerList.forEach(Observer::update);
}
}
抽象观察者
/**
* 观察者接口
*
* @author Administrator
**/
public interface Observer {
/**
* 收到通知的更新操作
*/
void update();
}
具体观察者
/**
* 具体观察者
*
* @author Administrator
**/
public class ConcreteObserver implements Observer{
@Override
public void update() {
// 更新的逻辑
}
}
当然,我们也可以改成第二种方案,将抽象主题改成抽象类,这样就可以由抽象角色来持有观察者的聚集引用,而且管理聚集的增删方法也可以直接在
抽象主题中直接实现,这样子类只需要很轻量级的代码了:
有了上面的基础,我们来看Java对观察者的原生支持:
Java的API还为为我们提供现成的Observer接口Java.util.Observer。我们只要直接使用它就可以。
先看这个Observer接口:
这个接口比较简单,我们直接看陌生的面孔——update()的参数类型:Observable,看它的介绍:
看完文字的介绍我们也可以通过查看源码更加清晰的认识这个类
接下来我们举一个栗子:假设一个商品的价格变更了应该通知它的观察者:——使用的是UML简图的方案二
被观察者,产品:
/**
* 具体被观察者
*
* @author Administrator
**/
public class Product extends Observable{
private String name;
private float price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
// 设置通知
setChanged();
notifyObservers(name);
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
setChanged();
notifyObservers(new Float(price));
}
}
两个观察者:
/**
* name观察者
*
* @author Administrator
**/
public class NameObserver implements java.util.Observer{
@Override
public void update(Observable o, Object arg) {
System.out.println(o);
String name;
if (arg instanceof String) {
name = (String) arg;
// 变更的逻辑
System.out.println("产品名称已经变更为:" + name);
}
}
}
/**
* price观察者
*
* @author Administrator
**/
public class PriceObserver implements java.util.Observer{
@Override
public void update(Observable o, Object arg) {
System.out.println(o);
float price;
if (arg instanceof Float) {
// 变更逻的辑
price = (Float) arg;
System.out.println("产品价格变更为:" + price);
}
}
}
客户端:
/**
* 客户端
* @author Administrator
**/
public class Client {
public static void main(String[] args) {
// 下面调用了新增的方法,无法使用多态声明
Product product = new Product();
java.util.Observer nameObserver = new NameObserver();
java.util.Observer priceObserver = new PriceObserver();
// 增加观察者
product.addObserver(nameObserver);
product.addObserver(priceObserver);
product.setName("小西瓜");
product.setPrice(100.1f);
}
}
// 这里第一个未使用到的参数就是抽象被观察者了,当然这里由于产品子类有新增方法,故不能调用新增方法
而且,这里是通知了所有的观察者