观察者模式

Publish/Subscribe模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己.
意图是解除耦合,让耦合的双方都依赖抽象,而不依赖具体.

1
2
3
4
5
6
7
8
9
package observer;

/**
* Created by hero on 17-2-18.
*/
public interface Observer {
void update();
}

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

/**
* Created by hero on 17-2-18.
*/
public class StockObserver implements Observer {
private String name;
private Subject subject;

public void update() {
System.out.println(subject.getState() + ": " + name + " 快别看股票了.");
}

public StockObserver(String name, Subject subject) {
this.name = name;
this.subject = subject;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
package observer;

/**
* Created by hero on 17-2-18.
*/
public class FootballObserver implements Observer {

public void update() {
System.out.println("停止看足球,继续工作.");
}
}

1
2
3
4
5
6
7
8
9
10
11
12
package observer;

/**
* Created by hero on 17-2-18.
*/
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyALL();
String getState();
}

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
package observer;

import java.util.LinkedList;
import java.util.List;

/**
* Created by hero on 17-2-18.
*/
public class Secretary implements Subject {
private List<Observer> observers = new LinkedList<Observer>();
public String state;

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

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

public void notifyALL() {
for (Observer observer : observers) {
observer.update();
}
}

public String getState() {
return state;
}
}

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

/**
* Created by hero on 17-2-18.
*/
public class Main {
public static void main(String[] args) {
Secretary secretary = new Secretary();
FootballObserver jack = new FootballObserver();
StockObserver lucy = new StockObserver("lucy", secretary);

secretary.attach(jack);
secretary.attach(lucy);
secretary.detach(jack);

secretary.state = "老板来了";

secretary.notifyALL();
}
}

事件委托

观察者模式的不足:

  • 通知者还是要依赖抽象的观察者.
  • 各个观察者的不同行为都命名为update,不符合实际.
  • 每个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 com.think.reflect;

import java.lang.reflect.Method;

/**
* Created by hero on 17-2-19.
*/
public class MyEvent {
private Object object;
private Method method;
private Object[] paras;

public MyEvent(Object object, Method method, Object[] paras) {
this.object = object;
this.method = method;
this.paras = paras;
}

public Object getObject() {
return object;
}

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

public Method getMethod() {
return method;
}

public void setMethod(Method method) {
this.method = method;
}

public Object[] getParas() {
return paras;
}

public void setParas(Object[] paras) {
this.paras = paras;
}
}

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
package com.think.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

/**
* Created by hero on 17-2-19.
*/
public class EventHandler {
private List<MyEvent> observers = new LinkedList<MyEvent>();

public void band(Object object, String strMethod, Object... paras) {
try {
Method method = object.getClass().getMethod(strMethod, constrainTypes(paras));
MyEvent myEvent = new MyEvent(object, method, paras);
observers.add(myEvent);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}

public void notifyALL() {
for (MyEvent myEvent : observers) {
try {
myEvent.getMethod().invoke(myEvent.getObject(), myEvent.getParas());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}

private Class[] constrainTypes(Object[] paras) {
if (paras == null) return null;
Class[] paraTypes = new Class[paras.length];
int i = 0;
for (Object object : paras) {
paraTypes[i++] = object.getClass();
}
return paraTypes;
}
}

1
2
3
4
5
6
7
8
9
10
11
package com.think.reflect;

/**
* Created by hero on 16-7-30.
*/
public class A {
public void shut() {
System.out.println("boss come, a");
}
}

1
2
3
4
5
6
7
8
9
10
11
12
package com.think.reflect;


/**
* Created by hero on 16-7-30.
*/
public class B {
public void wake(Integer time, String name) {
System.out.println("boss come, b " + time + " " + name);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.think.reflect;

/**
* Created by hero on 17-2-19.
*/
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();

EventHandler bossComeEventHandler = new EventHandler();

bossComeEventHandler.band(a, "shut");
bossComeEventHandler.band(b, "wake", 1, "小明");

bossComeEventHandler.notifyALL();
}
}