观察者模式(未完成)

观察者模式

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

观察者模式结构图

3.6.x 案例

  秘书通知职员老板来审查工作了,初步实现。

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
56
57
58
59
60
61
62
63
//前台秘书
public class Secretary {
//同时列表
private List<StockObserver> observers = new ArrayList<>();
private String action;

//增加
public void attach(StockObserver observer){
observers.add(observer);
}

//通知
public void notifyy(){
for (StockObserver observer : observers){
observer.update();
}
}

public String getSecretaryAction(){
return action;
}
public void setSecretaryAction(String value){
action = value;
}
}

//看股票的同事
public class StockObserver {
private String name;
private Secretary sub;

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

public void update(){
System.out.println(sub.getSecretaryAction() + name + " 关闭股票行情,继续工作!");
}
}

public class Main {
public static void main(String[] args) {
//模拟前台通知摸鱼职员躲避老板审查工作

//前台小姐
Secretary qiantai = new Secretary();
//看股票的同事
StockObserver tongshi1 = new StockObserver("张三",qiantai);
StockObserver tongshi2 = new StockObserver("李四",qiantai);

//前台登记两名同事
qiantai.attach(tongshi1);
qiantai.attach(tongshi2);

//发现老板回来
qiantai.setSecretaryAction("老板回来了!");
//发送通知
qiantai.notifyy();

//此结构下前台和同事两类相互耦合,难以扩展
}
}

  根据观察者模式进行解耦。

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
public abstract class Observer {
protected String name;
protected Subject sub;

public Observer(String name, Subject sub) {
this.name = name;
this.sub = sub;
}

public abstract void update();
}

public class StockObserver extends Observer {
public StockObserver(String name, Subject sub) {
super(name,sub);
}

public void update(){
System.out.println(this.sub.getSecretaryAction() + this.name + " 关闭股票行情,继续工作!");
}
}

public class NBAObserver extends Observer {
public NBAObserver(String name, Subject sub) {
super(name,sub);
}

public void update(){
System.out.println(this.sub.getSecretaryAction() + this.name + " 关闭NBA直播,继续工作!");
}
}

//通知者接口
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyy();
String getSecretaryAction();
void setSecretaryAction(String value);
}

public class Boss implements Subject {
private List<Observer> observers = new ArrayList<>();
private String action;

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

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

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

@Override
public String getSecretaryAction(){
return action;
}

@Override
public void setSecretaryAction(String value){
action = value;
}
}

//前台秘书
public class Secretary {
//针对抽象编程,减少了和具体类的耦合
//同时列表
private List<Observer> observers = new ArrayList<>();
private String action;

//增加
public void attach(Observer observer){
observers.add(observer);
}

//减少
public void detach(Observer observer){
observers.remove(observer);
}

//通知
public void notifyy(){
for (Observer observer : observers){
observer.update();
}
}

public String getSecretaryAction(){
return action;
}
public void setSecretaryAction(String value){
action = value;
}
}

public class Test {
public static void main(String[] args) {
Boss boss = new Boss();

StockObserver tongshi1 = new StockObserver("张三",boss);
NBAObserver tongshi2 = new NBAObserver("李四",boss);

boss.attach(tongshi1);
boss.attach(tongshi2);

boss.detach(tongshi1);

boss.setSecretaryAction("老板回来了!");
boss.notifyy();
}
}

3.6.x 代码结构

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/**
* 主题,或抽象通知者
* 一般用一个抽象类或一个接口实现。
* 它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。
* 抽象主题提供一个接口
*/
public abstract class Subject {
private List<Observer> observers = new ArrayList<>();

//增加
public void attach(Observer observer){
observers.add(observer);
}

//减少
public void detach(Observer observer){
observers.remove(observer);
}

//通知
public void notifyy(){
for (Observer observer : observers){
observer.update();
}
}
}

/**
* 抽象观察者
* 为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。
* 这个接口叫更新接口。抽象观察者一般用一个抽象类或者一个接口实现。
* 更新接口通常包含一个update方法,叫做更新方法
*/
public abstract class Observer {
public abstract void update();
}

/**
* 具体主题,或具体通知者
* 将有关状态存入具体观察者对象;
* 在具体主题的内部状态改变时,给所有登记过的观察者发出通知
*/
public class ConcreteSubject extends Subject {
private String subjectState;
//具体被观察者状态

public String getSubjectState() {
return subjectState;
}

public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
}
}


/**
* 具体观察者
* 实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。
* 具体观察者角色可以保存一个指向具体主题对象的引用。
* 具体观察者角色通常用一个具体子类实现
*/
public class ConcreteObserver extends Observer {
private String name;
private String observerState;
private ConcreteSubject subject;

public ConcreteObserver(String name, ConcreteSubject subject) {
this.name = name;
this.subject = subject;
}

@Override
public void update() {
observerState = subject.getSubjectState();
System.out.println("观察者" + name + "的新状态是" + observerState);
}

public ConcreteSubject getSubject() {
return subject;
}

public void setSubject(ConcreteSubject subject) {
this.subject = subject;
}
}

/**
* 客户端代码
*/
public class Main {
public static void main(String[] args) {
ConcreteSubject s = new ConcreteSubject();

s.attach(new ConcreteObserver("X",s));
s.attach(new ConcreteObserver("Y",s));
s.attach(new ConcreteObserver("Z",s));
s.setSubjectState("ABC");
s.notifyy();
}
}

3.6.x 适用场景

  将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使得各类紧密耦合,这样会给维护、扩展和重用都带来不便。

  关键对象在于主题Subject和观察者Observer,一个主题对应多个观察者,主题不需要知道具体谁是其观察者,只要推送即可使所有观察者收到通知。

  当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。

  当一个抽象模型有两个方面,一个方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。

3.6.x 特点

  观察者模式所做的工作其实就是解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的变化,即依赖倒转原则的具体应用。

3.6.x 不足

  当观察者无法统一抽象,没有相同的方法,当收到通知时行为各不相同,主题和观察者互相没有联系,观察者模式很难去实现。

  此时观察者无法建立统一的抽象类或接口,主题也无法声明观察者的增减方法。

3.6.x 事件委托

  可以通过事件委托来解决观察者模式的不足,比如通知者可以完全不知道观察者的存在,完全解耦;一次通知可以使不同的观察者执行不同的方法等。

  委托就是一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的‘类’,委托的实例将代表一个具体的函数。

  一个委托可以搭载多个方法,所有方法被依次唤起,可以使得委托对象所搭载的方法并不需要属于同一个类。但委托对象所搭载的所有方法必须具有相同的原型和形式,也就是拥有相同的参数列表和返回值类型。

  通过事件委托机制改写案例如下。Java没有.NET中的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
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
public class NBAObserver {
private String name;

public NBAObserver(String name) {
System.out.println("我是" + name + ",开始看NBA直播");
this.name = name;
}

public void closeNBADirectSeeding(){
System.out.println(this.name + " 关闭NBA直播,继续工作!");
}
}

public class StockObserver {
private String name;

public StockObserver(String name) {
System.out.println("我是" + name + ",开始看股票行情");
this.name = name;
}

public void closeStockMarket(){
System.out.println(this.name + " 关闭股票行情,继续工作!");
}
}

public abstract class Subject {
private EventHandler eventHandler = new EventHandler();
public abstract void notifyy();

public EventHandler getEventHandler() {
return eventHandler;
}

public abstract void addObserver(Object o,String methodName,Object... args);

public void setEventHandler(EventHandler eventHandler) {
this.eventHandler = eventHandler;
}
}

public class Boss extends Subject {
private String action;

@Override
public void notifyy() {
System.out.println("委托人通知老板来了");
try {
EventHandler handler = this.getEventHandler();
handler.notifyy();
}catch (Exception ex){
ex.printStackTrace();
}
}

@Override
public void addObserver(Object o, String methodName, Object... args) {
System.out.println("委托人新增被通知人");
try {
EventHandler handler = this.getEventHandler();
handler.addEvent(o,methodName,args);
}catch (Exception ex){
ex.printStackTrace();
}
}
}

public class EventHandler {
//是用一个List
private List<Event> objects;

public EventHandler(){
objects=new ArrayList<Event>();
}

//添加某个对象要执行的事件,及需要的参数
public void addEvent(Object object,String methodName,Object...args){
objects.add(new Event(object,methodName,args));
}

//通知所有的对象执行指定的事件
public void notifyy() throws Exception{
for(Event e : objects){
e.invoke();
}
}
}

public class Event {
//要执行方法的对象
private Object object;
//要执行的方法名称
private String methodName;
//要执行方法的参数
private Object[] params;
//要执行方法的参数类型
private Class[] paramTypes;

public Event(){
}

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

//根据参数数组生成参数类型数组
private void contractParamTypes(Object[] params){
this.paramTypes=new Class[params.length];
for(int i=0;i<params.length;i++){
this.paramTypes[i]=params[i].getClass();
}
}


public Object getObject() {
return object;
}

public void setObject(Object object) {
this.object = object;
}

public String getMethodName() {
return methodName;
}

public void setMethodName(String methodName) {
this.methodName = methodName;
}

public Object[] getParams() {
return params;
}

public void setParams(Object[] params) {
this.params = params;
}

public Class[] getParamTypes() {
return paramTypes;
}

public void setParamTypes(Class[] paramTypes) {
this.paramTypes = paramTypes;
}

/**
* 根据该对象的方法名,方法参数,利用反射机制,执行该方法
* @throws Exception
*/
public void invoke() throws Exception{
Method method = object.getClass().getMethod(this.getMethodName(),
this.getParamTypes());
if(null==method){
return;
}
method.invoke(this.getObject(), this.getParams());
}
}

/**
* 客户端代码
*/
public class Main {
public static void main(String[] args) {
Subject s = new Boss();
NBAObserver nba = new NBAObserver("X");
StockObserver stock = new StockObserver("Y");
s.addObserver(nba,"closeNBADirectSeeding");
s.addObserver(stock,"closeStockMarket");
s.notifyy();
}
}

参考:

🔗 《设计模式:可复用面向对象软件的基础》

🔗 《大话设计模式》