基本定义:观察者模式是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实作事件处理系统。
实例:公司前台,观察老板动向
源代码:
package observer;
import java.util.ArrayList;
public class observer {
public static void main(String[] args) {
// TODO Auto-generated method stub
Secretary dabao =new Secretary();//前台秘书大宝
//看股票同事
StockObserver per1 =new StockObserver("小明",dabao);
StockObserver per2 =new StockObserver("小红",dabao);
//前胎记下两位同事
dabao.Attach(per1);
dabao.Attach(per2);
//发现老板回来
dabao.setAction("老板回来了");
//通知两个同事
dabao.Notify();
}
}
class Secretary//前台秘书类——Sercretary依赖StockObserver
{//同时列表组合,用来添加请求帮忙的同事
private ArrayList<StockObserver> observers = new ArrayList<StockObserver>();
private String action;
public void Attach(StockObserver observer ) {
observers.add(observer);
}
public void Notify()//通过
{
for(int i=0;i<observers.size();i++)
{
observers.get(i).Update();
}
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action=action;
}
}
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.getAction()+name+"关闭股票性情,继续工作!");
}
}
改进:耦合度太高,抽象类实现解耦合
package observer;
import java.util.ArrayList;
import java.util.Observable;
public class observer2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Subject dabao =new Boss();
//看股票同事
StockObserver per1 =new StockObserver("小明",dabao);
NBAObserver per2 =new NBAObserver("小红",dabao);
//前胎记下两位同事
dabao.Attach(per1);
dabao.Attach(per2);
//发现老板回来
dabao.setAction("老板回来了");
//通知两个同事
dabao.Notify();
}
}
abstract class Subject//抽象通知者
{//同时列表组合,用来添加请求帮忙的同事
abstract void Attach(Observer observer);//添加观察者
abstract void Detach(Observer observer);//删除观察者
abstract void Notify();//通知观察者
private String action;
public String getAction() {//老板状态
return action;
}
public void setAction(String action) {
this.action=action;
}
}
class Boss extends Subject{
private ArrayList<Observer> observers = new ArrayList<Observer>();
@Override
void Attach(Observer observer) {
// TODO Auto-generated method stub
observers.add(observer);
}
@Override
void Detach(Observer observer) {
// TODO Auto-generated method stub
observers.remove(observer);
}
@Override
void Notify() {
// TODO Auto-generated method stub
for(int i=0;i<observers.size();i++) {
observers.get(i).Update();
}
}
}
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();
}
class StockObserver extends Observer{
public StockObserver(String name, Subject sub) {
super(name, sub);
// TODO Auto-generated constructor stub
}
@Override
public void Update() {
// TODO Auto-generated method stub
//观察者类需要前台的状态
System.out.println(sub.getAction()+name+"关闭股票性情,继续工作!");
}
}
class NBAObserver extends Observer{
public NBAObserver(String name, Subject sub) {
super(name, sub);
// TODO Auto-generated constructor stub
}
@Override
public void Update() {
// TODO Auto-generated method stub
System.out.println(sub.getAction()+name+"关闭NBA,继续工作!");
}
}
观察者模式模板:
package observer;
import java.util.ArrayList;
public class observer3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
ConcreteSubject dabao =new ConcreteSubject();
dabao.Attach(new ConcreObserver("X",dabao));
dabao.Attach(new ConcreObserver("Y",dabao));
dabao.Attach(new ConcreObserver("Z",dabao));
dabao.setAction("ABC");
dabao.Notify();
}
}
abstract class Subject//抽象通知者
{//同时列表组合,用来添加请求帮忙的同事
private ArrayList<Observer> observers = new ArrayList<Observer>();
public void Attach(Observer observer)//添加观察者
{
observers.add(observer);
}
public void Detach(Observer observer){
observers.remove(observer);
}//删除观察者
public void Notify()//通知观察者
{
for(int i=0;i<observers.size();i++) {
observers.get(i).Update();
}
}
}
class ConcreteSubject extends Subject{
private String action;
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
}
abstract class Observer{//看股票同事类
abstract void Update();
}
class ConcreObserver extends Observer{
private String name;
private String action;
private ConcreteSubject sub;
public ConcreObserver(String name, ConcreteSubject sub) {
super();
this.name = name;
this.sub = sub;
}
@Override
void Update() {
// TODO Auto-generated method stub
this.action=sub.getAction();
System.out.println("观察者"+name+"的新的状态是"+action);
}
}
JAVA中的观察者案例
狼来了——源代码:
package observer;
import java.util.Observer;
import java.util.Observable;
public class observer4 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Wolf wolf =new Wolf("狼");
Sheep sheep1 =new Sheep("羊1");
Sheep sheep2 =new Sheep("羊2");
Sheep sheep3 =new Sheep("羊3");
//注册观察者,sheep1和2加入3不加入;
wolf.addObserver(sheep1);
wolf.addObserver(sheep2);
String state="饿";
wolf.shout(state);
}
}
class Wolf extends Observable{//被观察者类
private String name;
Wolf(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void shout(String state) {
System.out.println(this.getName()+"shouting");
this.setChanged(); this.notifyObservers(state);
}
}
class Sheep implements Observer{
private String state ="eating";
private String name;
public Sheep(String name) {
super();
this.name = name;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void update(Observable arg0, Object arg1) {
// TODO Auto-generated method stub
Wolf w=(Wolf)arg0;
System.out.println(w.getName()+"shouting and"+arg1+" "+this.getName()+"running------");
setState("running");
}
}
观察者模式的应用
1. 何时使用
- 一个对象状态改变,所有的依赖对象都将得到通知
2. 方法
- 使用面向对象技术
3. 优点
- 观察者和被观察者是抽象耦合的
- 建立了一套触发机制
4. 缺点
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
- 如果观察者和观察目标间有循环依赖,可能导致系统崩溃
- 没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的
5. 使用场景
- 关联行为场景
- 事件多级触发场景
- 跨系统的消息变换场景,如消息队列的处理机制
6. 应用实例
- 手机丢了,委托别人给其他人发消息通知
- 通知老师/老板来了
- 拍卖,拍卖师观察最高标价,然后通知给其它竞价者竞价
- 在一个目录下建立一个文件,会同时通知目录管理器增加目录,并通知磁盘减少空间,文件是被观察者,目录管理器和磁盘管理器是观察者
- 猫叫了一声,吓着了老鼠,也惊到了主人,猫是被观察者,老鼠和人是观察者
7. 注意事项
- 避免循环引用
- 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式