Java实现23种设计模式(十六):观察者模式(重点掌握)
2020-06-11 本文已影响0人
依然慢节奏
二十三种设计模式分类
设计模式三大分类.jpg一、概述
观察者(Observer
)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。
主要意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
优点
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
- 目标与观察者之间建立了一套触发机制。
缺点
- 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
- 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
场景
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 需要在系统中创建一个触发链,
A
对象的行为将影响B
对象,B
对象的行为将影响C
对象……,可以使用观察者模式创建一种链式触发机制。
二、实现
1. 结构图
观察者模式的主要角色如下。
- 抽象主题(
Subject
)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。 - 具体主题(
Concrete Subject
)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。 - 抽象观察者(
Observer
)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。 - 具体观察者(
Concrete Observer
)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
PS
:UML
结构图可以参考,例子实现并不根据UML
图来完成,灵活实现即可;
2. 实现
2.1 自己实现观察者模式
- 观察者接口
package cn.missbe.model.observer.primitive;
/**
* Copyright (c) 2020.
* Email: love1208tt@foxmail.com
* @author lyg 2020/4/27 下午10:28
* description:
**/
public interface Observer {
/**
* 观察者接口,叫醒后发生的行为
* @param event 叫醒事件
*/
void actionWakeUp(WakeEvent event);
}
- 通知事件类
package cn.missbe.model.observer.primitive;
/**
* Copyright (c) 2020.
* Email: love1208tt@foxmail.com
* @author lyg 2020/4/27 下午10:28
* description: 简单封装的一个事件类
**/
public class WakeEvent {
/**叫醒发生时间点*/
private long timestamp;
/**叫醒时所处的位置*/
private String location;
/**源对象*/
private Object source;
public WakeEvent(long timestamp, String location, Object source) {
this.timestamp = timestamp;
this.location = location;
this.source = source;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public Object getSource() {
return source;
}
public void setSource(Object source) {
this.source = source;
}
@Override
public String toString() {
return "WakeEvent{" + "timestamp=" + timestamp + ", location='" + location + '\'' + ", source=" + source + '}';
}
}
- 多个观察者
package cn.missbe.model.observer.primitive;
/**
* Copyright (c) 2020.
* Email: love1208tt@foxmail.com
* @author lyg 2020/4/27 下午10:33
* description:观察都:Mum
**/
public class Mum implements Observer{
/**Mum针对孩子醒了以后的处理方式*/
private void hug(){
System.out.println("Mus hug wu wu...");
}
@Override
public void actionWakeUp(WakeEvent event) {
hug();
}
}
package cn.missbe.model.observer.primitive;
/**
* Copyright (c) 2020.
* Email: love1208tt@foxmail.com
* @author lyg 2020/4/27 下午10:34
* description:观察者:Dad
**/
public class Dad implements Observer {
/**Dad针对孩子醒了以后的处理方式*/
private void feed(){
System.out.println("Dad feed wu wu....");
}
@Override
public void actionWakeUp(WakeEvent event) {
feed();
}
}
package cn.missbe.model.observer.primitive;
/**
* Copyright (c) 2020.
* Email: love1208tt@foxmail.com
* @author lyg 2020/4/27 下午10:35
* description:观察者:Dog
**/
public class Dog implements Observer {
/**狗针对孩子醒了以后的处理方式*/
private void call(){
System.out.println("Dog wang wang...");
}
@Override
public void actionWakeUp(WakeEvent event) {
call();
}
}
- 具体通知者
package cn.missbe.model.observer.primitive;
import java.util.ArrayList;
import java.util.List;
/**
* Copyright (c) 2020.
* Email: love1208tt@foxmail.com
*
* @author lyg 2020/4/27 下午10:36
* description: 简单具体目标,进行通知
**/
public class ChildSubject {
/**观察者集合*/
List<Observer> observers = new ArrayList<>();
/**孩子是否cry*/
private boolean cry;
public void attach(Observer observer) {
observers.add(observer);
}
public void wakeUp() {
cry = true;
WakeEvent event = new WakeEvent(System.currentTimeMillis(), "bed", this);
for (Observer observer : observers) {
observer.actionWakeUp(event);
}
cry = false;
}
}
- 主类,调用测试
package cn.missbe.model.observer.primitive;
/**
* Copyright (c) 2020.
* Email: love1208tt@foxmail.com
* @author lyg 2020/4/27 下午10:39
* description:
* 观察者模式:同一事件发生,不同的观察都有不同的响应处理方式;
**/
public class Main {
public static void main(String[] args) {
ChildSubject subject = new ChildSubject();
/*添加观察者Mum*/
subject.attach(new Mum());
/*添加观察者Dad*/
subject.attach(new Dad());
/*添加观察者Dog*/
subject.attach(new Dog());
/*发生叫醒事件,通知所有观察者*/
subject.wakeUp();
}
}
2.1 利用JDK
实现观察者模式
- 被观察对象,实现
Observable
接口
package cn.missbe.model.observer.javax;
import java.util.Observable;
/**
* Copyright (c) 2020.
* Email: love1208tt@foxmail.com
* @author lyg 2020/4/27 下午10:26
* description:被观察者(Observable)
* ///设置变化点,表示被观察者状态已经发生了变化
* setChanged();
* ///如果该对象发生了变化,由所示hasChanged方法,则通知其所有观察者,并调用clearChanged方法来指示该对象不再改变
* notifyObservers(args);
**/
public class Earth extends Observable {
private String weather = "晴朗";
public String getWeather() {
return weather;
}
public void setWeather(String weather) {
this.weather = weather;
///设置变化点
setChanged();
///通知观察者
notifyObservers(weather);
}
@Override
public String toString() {
return "Earth{" +
"weather='" + weather + '\'' +
'}';
}
}
- 观察者,实现
Observer
接口
package cn.missbe.model.observer.javax;
import java.util.Observable;
import java.util.Observer;
/**
* Copyright (c) 2020.
* Email: love1208tt@foxmail.com
* @author lyg 2020/4/27 下午10:26
* description: 观察者:Satellite
* 当被观察者(Observable)状态发生变化时,观察者会捕捉到调用update方法
**/
public class Satellite implements Observer {
private String weather;
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
*/
@Override
public void update(Observable o, Object arg) {
weather = (String) arg;
System.out.println("近期天气变化:" + weather);
System.out.println("Observable:"+o);
}
}
- 主类,调用测试
package cn.missbe.model.observer.javax;
/**
* Copyright (c) 2020.
* Email: love1208tt@foxmail.com
* @author lyg 2020/4/27 下午10:26
* description:
**/
public class WeatherService {
public static void main(String[] args) {
Earth earth = new Earth();
Satellite satellite = new Satellite();
earth.addObserver(satellite);
System.out.println("-----天气预报------");
earth.setWeather("台风逼近....");
earth.setWeather("暴雨....");
earth.setWeather("火热....");
earth.setWeather("大风....");
}
}