引言
作为设计模式中常用的行为型模式,其主要解决的是一个复合对象(或组合对象)的基础依赖对象的通知问题。
简单的说,当一个复合对象依赖多个其他对象时,我们称这种关系为一对多的关系。当这个复合对象状态发生了改变,其他组成它的对象都可以收到来自复合对象的通知。
依赖对象中存在一个指向复合对象的引用。
实现步骤
实现参考《菜鸟教程——设计模式:观察者模式》
功能实现:实现一个进制转换器,它主要由一个包含二进制、八进制以及十六进制的基础转换器 List 和一个可变状态组成。通过观察者模式实现复合转换器到基础进制转换器的状态变更通知。
步骤一:定义基础组件及其抽象类
首先,定义一个基础转换器的抽象类BaseConverter,代码如下:
public abstract class BaseConverter {
/** 复合对象Converter的引用 */
protected Converter converter;
public abstract void update();
}
其次,定义具体实现的基础转换类:BinaryConverter、OctalConverter、HexConverter,代码如下:
public class BinaryConverter extends BaseConverter {
public BinaryConverter(Converter converter) {
this.converter = converter;
this.converter.attach(this);
}
@Override
public void update() {
System.out.println("Binary String : " + Integer.toBinaryString(converter.getState()));
}
}
public class OctalConverter extends BaseConverter {
public OctalConverter(Converter converter) {
this.converter = converter;
this.converter.attach(this);
}
@Override
public void update() {
System.out.println("Octal String : " + Integer.toOctalString(converter.getState()));
}
}
public class HexConverter extends BaseConverter {
public HexConverter(Converter converter) {
this.converter = converter;
this.converter.attach(this);
}
@Override
public void update() {
System.out.println("Hex String : " + Integer.toHexString(converter.getState()).toUpperCase());
}
}
步骤二:定义复合对象
复合对象Converter是一个由待转化的十进制数,和一个包含各种转化器的List组成的对象,我们的目的是:当state变量发生了变化后,baseConverters 中的每个对象都可以得知复合对象中state的变化。
public class Converter {
/** Converter 依赖于一个BaseConverter对象组成的List */
private List<BaseConverter> baseConverters = new ArrayList<>();
/** 一个可变的状态,观察者真正关心的可变对象 */
private int state;
public void attach(BaseConverter observer) {
baseConverters.add(observer);
}
/**
* 通知所有的观察者更新
*/
public void notifyAllConverters() {
for (BaseConverter cvter : baseConverters)
cvter.update();
}
// --------------GET/SET----------------
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyAllConverters();
}
}
步骤三:测试
public class ObserverPatternProgram {
public static void main(String[] args) {
Converter cvter = new Converter();
new HexConverter(cvter);
new OctalConverter(cvter);
new BinaryConverter(cvter);
System.out.println("第一个需要转化的十进制数是 : 15");
cvter.setState(15);
System.out.println("\n第二个需要转化的十进制数是 : 10");
cvter.setState(10);
}
}
输出结果是:
总结
我们的需求可能不局限于上述的代码功能,但观察者模式的实现基本一样,虽然不一定是包含一个List,而是单独的各个模块组成一个复合对象。但是,最关键的一点就是在依赖对象中一定要包含一个复合对象的引用。当复合对象的某些状态发生变化,那么复合对象就会告知依赖对象它们所关心的某些状态发生了变化。
这也正是“观察者”的真正含义,即依赖对象始终观察着包含在自己对象中的复合对象的引用。而复合对象需要做的,仅仅是在变更某些状态时,调用通知操作。
在本例中,可能会有读者觉得哪里有些别扭。
这是因为进制转换器的功能更像是一个人机交互的计算器功能,输入的数值不应该以对象的状态而存在。上述代码,我们通过一个可变的int 变量来存储这个将要被转化的十进制数,这可能就是读者觉得别扭的地方。把用户输入的数字封装成一个状态可能不是很恰当。但是我们大可跳出这个应用案例,去考虑更加一般的情况,如线程,那么这个复合对象的可变状态就可能是完全自主变化的任意类型的变量。所以从这个角度来讲我们也就能够更好的理解观察者模式,实际上观察者观察的就是封装在复合对象中的一个或多个状态,因此我们才会将用户输入的十进制数以状态的形式封装在进制转换器中。
由此,我们也可以总结实现观察者模式的几点要素:
1、复合对象必须具备一个或多个可变状态,否则观察将无从谈起;
2、依赖对象必须包含一个指向复合对象的引用,以便能够在接到通知时取得复合对象的可变状态;
3、复合对象和依赖对象必须具备依赖关系,这样复合对象才能够在状态变更时通知到它的依赖对象;
4、只有在复合对象的状态改变时才去通知依赖对象。
(扩展)5、依赖对象不一定需要取得复合对象的全部状态,复合对象的状态变更也不一定需要告知全部依赖对象。
鸣谢
《观察者模式》
综上,就是博主对观察者模式的理解,如有疑问,欢迎文末留言。