场景一:
老板出门回来的时候,前台秘书给大家打电话,大家马上各就各位,这样就不会被老板发现问题。
第一版代码(双向耦合)
前台秘书类:
package observer1;
import java.util.*;
public class secretary {
private List<observer> observers = new ArrayList<>();
private String action;
public void attach(observer o) {
//有几个同事请前台帮忙,就给集合增加几个对象
observers.add(o);
}
public void notity() {
for (observer o : observers) {
//给所有同事发通知
o.update();
}
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
}
看股票同事类:
package observer1;
public class observer {
private String name;
//秘书对象
private secretary s;
public observer(String name, secretary s) {
this.name = name;
this.s = s;
}
public void update(){
String format = String.format("%s,%s关闭股票,继续工作",s.getAction(),name);
System.out.println(format);
}
}
客户端:
package observer1;
public class client {
public static void main(String[] args) {
//前台秘书
secretary s = new secretary();
//看股票的两个同事
observer tongshi1 = new observer("zyy",s);
observer tongshi2 = new observer("yan",s);
s.attach(tongshi1);
s.attach(tongshi2);
//老板回来了
s.setAction("老板回来了");
//通知同事
s.notity();
}
}
但是两个类之间互相耦合,前台类要增加观察者,观察者类需要前台的状态,如果需要添加看NBA直播的同事,还需要改动前台类,违背了以下设计原则:
- 开放封闭原则 (对于拓展是开放的, 对于修改是封闭的)
- 依赖倒转原则 (程序都依赖抽象,而不是相互依赖)
第二版代码:
抽象观察者类(同事类):
package observer2;
public abstract class observer {
protected String name ;
protected secretary s;
public observer(String name, secretary s) {
this.name = name;
this.s = s;
}
public abstract void update();
}
具体观察者1(看股票的同事)
package observer2;
public class stockObserver extends observer {
public stockObserver(String name, secretary s) {
super(name, s);
}
@Override
public void update() {
String format = String.format("%s,%s关闭股票行情,继续工作",s.getAction(),name);
System.out.println(format);
}
}
具体观察者2(看NBA的同事)
package observer2;
public class NBAObserver extends observer{
public NBAObserver(String name, secretary s) {
super(name, s);
}
@Override
public void update() {
String format = String.format("%s,%s关闭股票行情,继续工作",s.getAction(),name);
System.out.println(format);
}
}
前台秘书类(把所有与具体观察者耦合的地方都改为“抽象观察者”)
package observer2;
import java.util.*;
public class secretary {
private List<observer> observers = new ArrayList<observer>();
private String action;
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public void attach(observer o) {
observers.add(o);
}
public void detach(observer o) {
observers.remove(o);
}
public void Notify() {
for (observer o : observers) {
o.update();
}
}
}
客户端:
package observer2;
public class client {
public static void main(String[] args) {
secretary s = new secretary();
stockObserver tongshi1 = new stockObserver("zyy",s);
NBAObserver tongshi2 = new NBAObserver("yan",s);
s.attach(tongshi1);
s.attach(tongshi2);
s.setAction("老板回来了");
s.Notify();
s.detach(tongshi1);
s.setAction("老板又来了");
s.Notify();
}
}
但是,这里前台秘书类是一个具体的类,也应该抽象出来,假如前台不在,老板就成了通知者
第三版代码:
通知者接口:
package observer3;
public interface subject {
void attach(observer o);
void detach(observer o);
void Notify();
String getAction();
}
具体通知者(老板)
package observer3;
import java.util.*;
public class boss implements subject {
private List<observer> observers = new ArrayList<>();
private String action;
@Override
public void attach(observer o) {
observers.add(o);
}
@Override
public void detach(observer o) {
observers.remove(o);
}
@Override
public void Notify() {
for (observer o : observers) {
o.update();
}
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
}
前台秘书类代码与老板类类似
对于观察者,需要改的地方就是把与前台耦合的地方都改为抽象通知者
抽象观察者:
package observer3;
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();
}
具体观察者(看股票的同事):
package observer3;
public class stockObserver extends observer {
public stockObserver(String name, subject sub) {
super(name, sub);
}
@Override
public void update() {
String format = String.format("%s,%s 关闭股票行情,继续工作",sub.getAction(),name);
System.out.println(format);
}
}
客户端:
package observer3;
public class client {
public static void main(String[] args) {
boss b = new boss();
stockObserver tongshi1 = new stockObserver("zyy",b);
stockObserver tongshi2 = new stockObserver("yan",b);
b.attach(tongshi1);
b.attach(tongshi2);
b.detach(tongshi1);
b.setAction("我回来了");
b.Notify();
}
}
上述代码的结构图为:
观察者模式:又叫发布——订阅模式
定义了一种一对多的依赖关系,让多个观察者(上述例子中的同事)同时监听某一个主题对象(上述例子中的前台秘书)。这个主题对象在状态发生变化时,会通知所有观察者对象。
Subject:主题或者抽象通知类,一般用一个抽象类或者一个接口实现。它将所有对观察者的引用保存在一个聚集中,每个通知类都可以有任意数量的观察者,可以增加和删除观察者对象。
再来看一个场景:
警察围捕嫌疑犯
观察者:便衣警察
通知类:嫌疑犯
(多个便衣警察观察嫌疑犯状态的变化)
具体代码:
观察者接口:
package observer_police;
public interface Observer {
void update(String message,String name);
}
具体观察者:
package observer_police;
public class Bianyi1 implements Observer {
private String bname = "bianyi1";
@Override
public void update(String message, String name) {
System.out.println(bname+":"+name+"那里有情况"+message);
}
}
其余具体观察者与之类似
通知者类接口:
package observer_police;
public interface xianyifan {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notice(String message);
}
具体通知者:
package observer_police;
import java.util.ArrayList;
import java.util.List;
public class xianyifan1 implements xianyifan {
private String name = "大熊";
private List<Observer> observerList = new ArrayList<Observer>();
@Override
public void addObserver(Observer observer) {
if(!observerList.contains(observer)){
observerList.add(observer);
}
}
@Override
public void removeObserver(Observer observer) {
if(observerList.contains(observer)){
observerList.remove(observer);
}
}
@Override
public void notice(String message) {
for(Observer observer:observerList){
observer.update(message,name);
}
}
}
其余通知者类与之类似
客户端:
package observer_police;
public class client {
public static void main(String[] args) {
xianyifan xyf1 = new xianyifan1();
xianyifan xyf2= new xianyifan2();
Observer o1 = new Bianyi1();
Observer o2 = new Bianyi2();
Observer o3 = new Bianyi3();
xyf1.addObserver(o1);
xyf1.addObserver(o2);
xyf1.addObserver(o3);
xyf2.addObserver(o2);
String message1 = "要逃跑";
String message2 = "已抓捕";
xyf1.notice(message1);
xyf2.notice(message2);
}
}
观察者模式的特点:
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性,我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、拓展和重用都带来不便。
观察者模式的关键对象是主题(通知者)和观察者,主题(通知者)可以有任意数目的依赖它的观察者,一旦主题的状态发生变化,所有依赖它的观察者都可以得到通知。主题发出通知时,并不知道谁是它的观察者,也就是说,具体观察者是谁,根本不需要知道。
何时用观察者模式?
当一个对象的改变需要同时改变其他对象,并且它不知道有多少对象需要改变。
观察者模式所做的工作就是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另外一边的变化。