设计模式-观察者模式

简介:

观察者模式分析

观察者模式又叫做发布-订阅(Publish/Subscribe)模式。
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

特点:
观察者模式的通知者可以有任意数目的依赖它的Observer,一旦通知者的状态改变,所有的Observer都可以得到通知。通知者发出通知时并不需要知道谁是它的观察者,也就是说,具体观察者是谁,它根本不需要知道。
总得来讲,观察者模式所做的工作其实就是在接触耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。

那么在观察者模式时,如果观察者之间非常相似,那么可以用抽象类来共用一些代码,但是现实编程中,具体的观察者完全有可能是风马牛不相及的类,但它们都需要根据通知者的通知来做出Update()操作,所以让它们都实现下面一个接口就可以实现这个想法了。

interface Observer {
    void update();
}

下面这个观察者模式,我会一步步以例子进行分析。
下面的观察者以工作中开小差玩游戏的同事为原型,通知者以秘书为原型,一旦老板出现,秘书立即通知玩游戏、睡觉的同事,做好准备。

双向耦合代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package observer1;

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

/**
* Created by benjamin on 1/4/16.
* 秘书类
*/

public class Secretary {
private List<PlayGameObserver> observers = new ArrayList<PlayGameObserver>(); //观察者的集合
private String noticeMessage; //通知的消息

public Secretary(){}

/**
* 增加观察者
* @param observer
*/

public void addObserver(PlayGameObserver observer) {
observers.add(observer);
}

/**
* 删除观察者
* @param observer
*/

public void removeObserver(PlayGameObserver observer) {
observers.remove(observer);
}

/**
* 通知所有观察者
*/

public void notifyObserver() {
for (PlayGameObserver o : observers) {
o.update();
}
}

public String getNoticeMessage() {
return noticeMessage;
}

public void setNoticeMessage(String noticeMessage) {
this.noticeMessage = noticeMessage;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package observer1;

/**
* Created by benjamin on 1/4/16.
* 玩游戏的观察者
*/

public class PlayGameObserver {

private String name; //玩游戏的观察者姓名
private Secretary sub; //通知者(秘书)

public PlayGameObserver(String name, Secretary sub) {
this.name = name;
this.sub = sub;
}

public void update() {
System.out.println(sub.getNoticeMessage() + this.name + "关闭游戏,继续工作!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package observer1;

/**
* Created by benjamin on 1/4/16.
*/

public class ObserverTest {

public static void main(String[] args) {
Secretary secretary = new Secretary();
PlayGameObserver o1 = new PlayGameObserver("王菲", secretary);
secretary.addObserver(o1);

secretary.setNoticeMessage("老板回来了!");
secretary.notifyObserver();
}
}

结果输出为:

老板回来了!王菲关闭游戏,继续工作!

上面的类虽然能实现功能,但是仔细一看,他们之间的耦合太大了。秘书类需要增加观察者,而观察者们需要秘书类。如果观察者不止一个人,并且干得事情不一样的时候(比如睡觉、吃东西什么的),就无法让秘书增加对应的观察者,并一起通知。我们来改改代码。

解耦

抽象观察者类(Observer)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package observer1;

/**
* Created by benjamin on 1/4/16.
* 观察者
*/

public abstract class Observer {

protected String name;
protected Notification notice;

public Observer(String name, Notification notice) {
this.name = name;
this.notice = notice;
}

public abstract void update(); //更新抽象类
}

抽象通知者类(Notification)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package observer1;

/**
* Created by benjamin on 1/4/16.
*/

public abstract class Notification {

protected String noticeMessage; //通知消息

public abstract void addObserver(Observer observer);
public abstract void removeObserver(Observer observer);
public abstract void notifyObserver();

public String getNoticeMessage() {
return noticeMessage;
}

public void setNoticeMessage(String noticeMessage) {
this.noticeMessage = noticeMessage;
}
}

观察者们

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package observer1;

/**
* Created by benjamin on 1/4/16.
* 玩游戏的观察者
*/

public class PlayGameObserver extends Observer {

public PlayGameObserver(String name, Notification notice) {
super(name, notice);
}

@Override
public void update() {
System.out.println(notice.noticeMessage + name + "关闭游戏,继续工作!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package observer1;

/**
* Created by benjamin on 1/4/16.
* 睡觉的观察者
*/

public class SleepObserver extends Observer {

public SleepObserver(String name, Notification notice) {
super(name, notice);
}

@Override
public void update() {
System.out.println(notice.noticeMessage + name + "停止睡觉,继续工作!");
}
}

通知者们

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package observer1;

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

/**
* Created by benjamin on 1/4/16.
* 秘书类
*/

public class Secretary extends Notification {
private List<Observer> observers = new ArrayList<Observer>(); //观察者集合

@Override
public void addObserver(Observer observer) {
observers.add(observer);
}

@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}

@Override
public void notifyObserver() {
for (Observer o : observers) {
o.update();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package observer1;

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

/**
* Created by benjamin on 1/4/16.
* 老板
*/

public class Boss extends Notification {
private List<Observer> observers = new ArrayList<Observer>(); //观察者集合

@Override
public void addObserver(Observer observer) {
observers.add(observer);
}

@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}

@Override
public void notifyObserver() {
for (Observer o : observers) {
o.update();
}
}
}

进行测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package observer1;

/**
* Created by benjamin on 1/4/16.
*/

public class ObserverTest {

public static void main(String[] args) {
// 第一次老板回来了,秘书通知
Secretary secretary = new Secretary();
PlayGameObserver o1 = new PlayGameObserver("王菲", secretary);
SleepObserver o2 = new SleepObserver("谢霆锋", secretary);
secretary.addObserver(o1);
secretary.addObserver(o2);

secretary.setNoticeMessage("老板回来了!");
secretary.notifyObserver();

System.out.println("------------------------------------");

// 第二次老板回来了,找秘书有事,秘书来不及通知,老板看见了,老板来通知
Boss huhansan = new Boss();
PlayGameObserver p1 = new PlayGameObserver("张柏芝", huhansan);
PlayGameObserver p2 = new PlayGameObserver("谢霆锋", huhansan);
SleepObserver p3 = new SleepObserver("王菲", huhansan);
huhansan.addObserver(p1);
huhansan.addObserver(p2);
huhansan.addObserver(p3);
huhansan.removeObserver(p3); //抓到一个

huhansan.setNoticeMessage("你们不好好工作!");
huhansan.notifyObserver();

/**
* 输出
* 老板回来了!王菲关闭游戏,继续工作!
老板回来了!谢霆锋停止睡觉,继续工作!
------------------------------------
你们不好好工作!张柏芝关闭游戏,继续工作!
你们不好好工作!谢霆锋关闭游戏,继续工作!
*/

}
}

观察者模式的不足

比如我们在使用Eclipse以及Xcode等一些编辑工具的时候,我们可能一个运行可以导致很多窗口隐藏或者出现,而且各个变化都涉及到不同的控件。那么我们要是想通知它们,不可能让它们都去实现Observer接口,因为这些控件早都已经被他们的制造商给封装了。

尽管我们用了依赖倒转原则,但是‘抽象通知者’还是依赖‘抽象观察者’,也就是说,万一没有了抽象观察者这样的接口,我这通知的功能就完不成了。另外就是每个具体观察者,它不一定要使用‘更新’这个方法,有可能是‘工具箱隐藏’方法,有可能是‘导航栏变色’等。这根本就是不同名的方法,这应该就是不足的地方吧。

运用事件委托delegate机制

委托就是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看做是对函数的抽象,是函数的“类”,委托的实例将代表一个具体的函数。
一个委托可以搭载多个方法,所有方法被依次唤起。更重要的是,它可以使得委托对象所搭载的方法并不需要属于同一个类。

刚刚的例子我们加上Event和EventHandler作为委托,修改代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package observer1;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
* Created by benjamin on 1/4/16.
*/

public class Event {

private Object object;
private String methodName;
private String[] params;
private Class[] paramTypes;

public Event(Object object, String methodName, String...params){
this.object = object;
this.methodName = methodName;
this.params = params;
resolveParams(this.params);
}

private void resolveParams(String[] params) {
int length = params.length;
paramTypes = new Class[length];
for (int i = 0; i < length; i ++) {
paramTypes[i] = params[i].getClass();
}
}

public void invoke() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method method = object.getClass().getMethod(methodName, paramTypes);
if (method == null) return;
method.invoke(object, params);
}

}
1
2
3
4
5
6
7
8
9
10
package observer1;

/**
* Created by benjamin on 1/4/16.
*/

public interface Delegate {

void addEvent(Event e);
void notifyX() throws Exception;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package observer1;

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

/**
* Created by benjamin on 1/4/16.
*/

public class EventHandler implements Delegate{
private List<Event> events = new ArrayList<Event>();

public EventHandler(){}

public void addEvent(Event e) {
events.add(e);
}

public void notifyX() throws Exception {
for (Event e : events) {
e.invoke();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package observer1;

/**
* Created by benjamin on 1/4/16.
*/

public abstract class Notification {

private Delegate delegate ;

public Notification(Delegate delegate) {
this.delegate = delegate;
}

public abstract void addListener(Object object, String methodName, String...params);
public abstract void notifyX();

public Delegate getDelegate() {
return this.delegate;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package observer1;

/**
* Created by benjamin on 1/4/16.
* 秘书类
*/

public class Secretary extends Notification {

public Secretary(Delegate delegate) {
super(delegate);
}

@Override
public void addListener(Object object, String methodName, String... params) {
this.getDelegate().addEvent(new Event(object, methodName, params));
}

@Override
public void notifyX() {
try {
this.getDelegate().notifyX();
} catch (Exception e) {
e.printStackTrace();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package observer1;

/**
* Created by benjamin on 1/4/16.
* 老板
*/

public class Boss extends Notification {

public Boss(Delegate delegate) {
super(delegate);
}

@Override
public void addListener(Object object, String methodName, String... params) {
this.getDelegate().addEvent(new Event(object, methodName, params));
}

@Override
public void notifyX() {
try {
this.getDelegate().notifyX();
} catch (Exception e) {
e.printStackTrace();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package observer1;

/**
* Created by benjamin on 1/4/16.
* 玩游戏的观察者
*/

public class PlayGameObserver {

private String gamer;

public PlayGameObserver(String name) {
gamer = name;
}

public void stopGame(String noticeMessage) {
System.out.println(noticeMessage + gamer + "关闭游戏,继续工作!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package observer1;

/**
* Created by benjamin on 1/4/16.
* 睡觉的观察者
*/

public class SleepObserver {

private String sleeper;

public SleepObserver(String name) {
sleeper = name;
}

public void stopSleep(String noticeMessage) {
System.out.println(noticeMessage + sleeper + "停止睡觉,继续工作!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package observer1;

import sun.jvm.hotspot.runtime.Threads;

/**
* Created by benjamin on 1/4/16.
*/

public class ObserverTest {

public static void main(String[] args) {
// 第一次老板回来了,秘书通知
Delegate delegate = new EventHandler();
Secretary secretary = new Secretary(delegate);
PlayGameObserver o1 = new PlayGameObserver("王菲");
SleepObserver o2 = new SleepObserver("谢霆锋");
secretary.addListener(o1, "stopGame", "老板来了!");
secretary.addListener(o2, "stopSleep", "老板来了!");

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
secretary.notifyX();

System.out.println("------------------------------------");

// 第二次老板回来了,找秘书有事,秘书来不及通知,老板看见了,老板来通知
Delegate delegate1 = new EventHandler();
Boss huhansan = new Boss(delegate1);
PlayGameObserver p1 = new PlayGameObserver("张柏芝");
PlayGameObserver p2 = new PlayGameObserver("谢霆锋");
SleepObserver p3 = new SleepObserver("王菲");
huhansan.addListener(p1, "stopGame", "你们不好好工作!");
huhansan.addListener(p2, "stopGame", "你们不好好工作!");
huhansan.addListener(p3, "stopSleep", "你们不好好工作!");

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
huhansan.notifyX();

/**
* 输出
* 老板回来了!王菲关闭游戏,继续工作!
老板回来了!谢霆锋停止睡觉,继续工作!
------------------------------------
你们不好好工作!张柏芝关闭游戏,继续工作!
你们不好好工作!谢霆锋关闭游戏,继续工作!
你们不好好工作!王菲停止睡觉,继续工作!
*/

}
}

最后总结:
1、通知者不知道玩游戏的和睡觉的存在,完全解耦。(功劳归功于Event和EventHandler)
2、老板来后,一次通知,并且通知的消息可以变化,执行不同的方法
3、扩展性很高,再来一个玩纸牌的加上就可以,告诉一下通知者。

目录
相关文章
|
11月前
|
设计模式 监控 Java
Kotlin - 改良设计模式 - 观察者模式
Kotlin - 改良设计模式 - 观察者模式
135 3
|
10月前
|
设计模式 存储 供应链
前端必须掌握的设计模式——观察者模式
观察者模式(Observer Pattern)是一种行为型设计模式,实现了一种订阅机制。它包含两个角色:**观察者**(订阅消息、接收通知并执行操作)和**被观察者**(维护观察者列表、发送通知)。两者通过一对多的关系实现解耦,当被观察者状态改变时,会通知所有订阅的观察者。例如,商店老板作为被观察者,记录客户的需求并在商品到货时通知他们。前端应用中,如DOM事件注册、MutationObserver等也体现了这一模式。
|
5月前
|
设计模式 消息中间件 存储
【设计模式】【行为型模式】观察者模式(Observer)
一、入门 什么是观察者模式? 观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会收到通知并自动更新。
285 9
|
11月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
|
设计模式 传感器
【设计模式】观察者模式(定义 | 特点 | Demo入门讲解)
【设计模式】观察者模式(定义 | 特点 | Demo入门讲解)
165 0
|
7月前
|
设计模式 消息中间件 存储
设计模式:观察者模式
观察者模式属于行为型设计模式,用于建立对象间的一对多依赖关系。当主题(Subject)状态变化时,所有依赖的观察者(Observer)会自动收到通知并更新。
|
11月前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
180 6
|
11月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
91 1
|
11月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
76 3