设计模式-观察者模式

简介:

观察者模式分析

观察者模式又叫做发布-订阅(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、扩展性很高,再来一个玩纸牌的加上就可以,告诉一下通知者。

目录
相关文章
|
25天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
|
2月前
|
设计模式 传感器
【设计模式】观察者模式(定义 | 特点 | Demo入门讲解)
【设计模式】观察者模式(定义 | 特点 | Demo入门讲解)
42 0
|
3天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
20 1
|
20天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
27 3
|
2月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
34 9
|
2月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
32 2
|
2月前
|
设计模式 监控 UED
设计模式之观察者模式
【10月更文挑战第12天】 观察者模式是一种行为型设计模式,定义了一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都会自动更新。主要由主题(被观察者)和观察者组成,实现对象间的松耦合,广泛应用于用户界面、事件驱动系统和数据监控等领域。
|
2月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
本教程详细讲解Kotlin语法,适合深入学习。对于快速掌握Kotlin,推荐“简洁”系列教程。本文特别介绍了观察者模式,包括使用Java API和Kotlin委托属性(如Delegates.observable)实现的方法,旨在帮助开发者更高效地实现和优化观察者模式的应用。
35 3
|
3月前
|
设计模式 Java 关系型数据库
设计模式——观察者模式
观察者模式介绍、观察者模式优化天气预报案例、JDK 的Observable类和Observer类
设计模式——观察者模式
|
2月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
33 0

热门文章

最新文章

  • 1
    设计模式转型:从传统同步到Python协程异步编程的实践与思考
    54
  • 2
    C++一分钟之-设计模式:工厂模式与抽象工厂
    46
  • 3
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    52
  • 4
    C++一分钟之-C++中的设计模式:单例模式
    62
  • 5
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    41
  • 6
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    65
  • 7
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    60
  • 8
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    42
  • 9
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    51
  • 10
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    114
  • 下一篇
    无影云桌面