观察者模式
程序设计的六大基本原则
在学习设计模式之前,为了不让设计模式显得很模式,我们还必须了解一个东西,那就是程序设计六大原则。
这些原则是指导模式的规则,我会给一些原则附上一个例子,来说明这个原则所要表达的意思,注意,原则是死的,人是活的,所以并不是要你完完全全遵守这些规则,只是在可能的情况下,请尽量遵守。
- 单一职责原则:描述的意思是每个类都只负责单一的功能,切不可太多,并且一个类应当尽量的把一个功能做到极致。
- 里氏替换原则:这个原则表达的意思是一个子类应该可以替换掉父类并且可以正常工作。
- 接口隔离原则:也称接口最小化原则,强调的是一个接口拥有的行为应该尽可能的小。
- 依赖倒置原则:这个原则描述的是高层模块不该依赖于低层模块,二者都应该依赖于抽象,抽象不应该依赖于细节,细节应该依赖于抽象。
- 迪米特原则:也称最小知道原则,即一个类应该尽量不要知道其他类太多的东西,不要和陌生的类有太多接触。
- 开-闭原则:最后一个原则,一句话,对修改关闭,对扩展开放。
观察者模式的定义
观察者模式(有时又被称为发布-订阅模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实作事件处理系统。
上面的定义当中,主要有这样几个意思,首先是有一个目标的物件,通俗点讲就是一个类,它管理了所有依赖于它的观察者物件,或者通俗点说是观察者类,并在它自己状态发生变化时,主动发出通知。简单点概括成通俗的话来说,就是一个类管理着所有依赖于它的观察者类,并且它状态变化时会主动给这些依赖它的类发出通知。
观察者模式的实现
Hobbits和Orcs这两种人对天气的变化及敏感,四季的变化需要及时的让这两类人感知,他们对四季的变化可以及时的采取措施来应对天气变化。下面用代码实现这种模式:
首先定义一个统一的观察者接口:
/**
* 这个接口是为了提供一个统一的观察者做出相应行为的方法
*
* @param <S> Observable
* @param <O> Observer
* @param <A> Action
*/
public interface Observer<S extends Observable<S, O, A>, O extends Observer<S, O, A>, A> {
void update(S subject, A argument);
}
观察者接口适配接口race
public interface Race extends Observer<GWeather, Race, WeatherType> {
}
抽象观察者,持有观察者列表:
/**
* 抽象观察者
*
* @param <S> Subject
* @param <O> Observer
* @param <A> Argument type
*/
public abstract class Observable<S extends Observable<S, O, A>, O extends Observer<S, O, A>, A> {
protected List<O> observers;
public Observable() {
this.observers = new CopyOnWriteArrayList<>();
}
public void addObserver(O observer) {
this.observers.add(observer);
}
public void removeObserver(O observer) {
this.observers.remove(observer);
}
/**
* 广播,通知所有的观察者,天气有变
*/
@SuppressWarnings("unchecked")
public void notifyObservers(A argument) {
for (O observer : observers) {
observer.update((S) this, argument);
}
}
}
/**
*
* 天气类型的枚举类
*
*/
public enum WeatherType {
SUNNY, RAINY, WINDY, COLD;
@Override
public String toString() {
return this.name().toLowerCase();
}
}
天气观察者,用以通知天气变化:
/**
*天气观察者,通知天气变化
*
*/
public class GWeather extends Observable<GWeather, Race, WeatherType> {
private WeatherType currentWeather;
public GWeather() {
currentWeather = WeatherType.SUNNY;
}
/**
* 让天气随着时间变化
*/
public void timePasses() {
WeatherType[] enumValues = WeatherType.values();
currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length];
System.out.println("The weather changed to {}." + currentWeather);
//事件广播,通知具体观察者,天气变化
notifyObservers(currentWeather);
}
}
Orcs具体观察者,每当天气变化,通知Orcs 做出具体update动作
/**
*
* GOrcs 具体天气观察者
*
*/
public class GOrcs implements Race {
@Override
public void update(GWeather weather, WeatherType weatherType) {
switch (weatherType) {
case COLD:
System.out.println("The orcs are freezing cold.");
break;
case RAINY:
System.out.println("The orcs are dripping wet.");
break;
case SUNNY:
System.out.println("The sun hurts the orcs' eyes.");
break;
case WINDY:
System.out.println("The orc smell almost vanishes in the wind.");
break;
default:
break;
}
}
}
Hobbits 具体观察者,每当天气变化,通知Hobbits 做出具体update动作
/**
*
* GHobbits 具体天气观察者
*
*/
public class GHobbits implements Race {
private static final Logger LOGGER = LoggerFactory.getLogger(GHobbits.class);
@Override
public void update(GWeather weather, WeatherType weatherType) {
switch (weatherType) {
case COLD:
System.out.println("The hobbits are shivering in the cold weather.");
break;
case RAINY:
System.out.println("The hobbits look for cover from the rain.");
break;
case SUNNY:
System.out.println("The happy hobbits bade in the warm sun.");
break;
case WINDY:
System.out.println("The hobbits hold their hats tightly in the windy weather.");
break;
default:
break;
}
}
}
/**
* 启动类
*
*/
public class App {
public static void main(String[] args) {
GWeather gWeather = new GWeather();
gWeather.addObserver(new GOrcs());
gWeather.addObserver(new GHobbits());
gWeather.timePasses();
gWeather.timePasses();
gWeather.timePasses();
gWeather.timePasses();
}
}
运行结果如下:
23:38:22.744 [main] INFO com.iluwatar.observer.App - --Running generic version--
The weather changed to {}.rainy
The orcs are dripping wet.
The hobbits look for cover from the rain.
The weather changed to {}.windy
The orc smell almost vanishes in the wind.
The hobbits hold their hats tightly in the windy weather.
The weather changed to {}.cold
The orcs are freezing cold.
The hobbits are shivering in the cold weather.
The weather changed to {}.sunny
The sun hurts the orcs' eyes.
The happy hobbits bade in the warm sun.
总结
观察者模式在实际开发中的应用很广泛,特别是在设计任务调度系统中,任务状态的变化需要对全局任务做事件广播,这就特别适合应用观察者模式。