您的位置:首页 > 其它

设计模式初探-观察者模式

2017-08-08 09:24 218 查看
观察者模式(OBSERVER),又称发布-订阅(Publish-Subscribe),依赖(Dependents),通过定义对象间的一对多的依赖关系,达到当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新,属于对象行为型模式。观察者模式在软件设计中很常用,比如经典的MVC模式,Model为目标类,View为观察者,Controller为更新管理器。首先更新管理器即控制器先将视图和模型建立关联关系,然后当模型数据改变时,这些改变会自动反映在视图上,从而达到了业务和显示分离的效果。Java默认支持观察者模式,AWT1.1之后版本,Servlet,SAX2的事件处理模型均为基于观察者模式的委托事件模型(Delegation
Event Model或DEM)。在DEM模型里面,主题(Subject)角色负责发布(publish)事件,而观察者角色向特定的主题订阅(subscribe)它所感兴趣的事件。当一个具体主题产生一个事件时,它就会通知所有感兴趣的订阅者。观察者模式提供了一种将发布者与订阅者松散地耦合在一起的联系形式,以及一种能够动态地登记、取消向一个发布者的订阅请求的办法。
一、使用场景
1、当一个抽象模型有两个方面,其中一个方面依赖于另一方面,将这两者封装在独立的对象中以使它们能够独立地改变和复用。
2、当对一个对象的改变需要同时改变其他对象,而又不知道具体有多少对象及这些对象是谁。
3、建立链式触发机制,A影响B,B影响C,C影响D等等。
二、UML图



三、Java实现

[java] view
plain copy

package study.patterns.observer;  

  

import java.text.SimpleDateFormat;  

import java.util.ArrayList;  

import java.util.Date;  

import java.util.List;  

/** 

 * 观察者模式 

 * @author qbg 

 */  

public class ObserverPattern {  

    public static void main(String[] args) {  

        ClockTimerSubject timer = new ClockTimerSubject();//目标  

        DigitalClock digital = new DigitalClock(timer);//观察者  

        BigBenClock bigben = new BigBenClock(timer);//观察者  

        TimerTask task = new TimerTask(timer);//定时任务  

        task.start();//启动定时任务  

    }  

}  

/** 

 * 抽象目标类  

 */  

abstract class Subject{  

    protected List<Observer> observers = new ArrayList<Observer>();  

      

    /** 

     *  注册观察者 

     */  

    public void attach(Observer obs){  

        observers.add(obs);  

    }  

      

    /** 

     * 删除观察者 

     */  

    public void detach(Observer obs){  

        observers.remove(obs);  

    }  

      

    /** 

     * 通知观察者的抽象方法 

     */  

    public abstract void notifyObs();  

}  

/** 

 * 具体目标类,每秒更新下自己的内部时间状态  

 */  

class ClockTimerSubject extends Subject{  

    private String time;  

      

    /** 

     * 具体通知方式,通知所有观察者 

     */  

    @Override  

    public void notifyObs() {  

        for(Observer obs : this.observers){  

            obs.update(this);  

        }  

    }  

  

    /** 

     * 更新time,并将改变通知给观察者 

     */  

    public void tick(){  

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  

        time = sdf.format(new Date());  

        notifyObs();  

    }  

      

    public String getTime() {  

        return time;  

    }  

  

    public void setTime(String time) {  

        this.time = time;  

    }  

}  

/** 

 * 观察者抽象接口,只有一个update方法  

 */  

interface Observer{  

    public void update(ClockTimerSubject subject);  

}  

/** 

 * 钟表绘制接口 

 */  

interface Widget{  

    public void draw();  

}  

/** 

 * 数字钟表,具体观察者 

 */  

class DigitalClock implements Widget,Observer{  

    private ClockTimerSubject subject;  

      

    /** 

     * 初始化目标,并将自己注册到该目标的观察者列表中  

     */  

    public DigitalClock(ClockTimerSubject subject){  

        this.subject = subject;  

        this.subject.attach(this);  

    }  

      

    /** 

     * 先检查发出通知的目标是否为自己注册过的,是则响应  

     */  

    @Override  

    public void update(ClockTimerSubject subject) {  

        if(this.subject == subject){  

            draw();  

        }  

    }  

  

    @Override  

    public void draw() {  

        System.out.println("电子闹钟为您报时:"+subject.getTime());  

    }  

}  

/** 

 * 大笨钟,具体观察者 

 */  

class BigBenClock implements Widget,Observer{  

private ClockTimerSubject subject;  

      

    /** 

     * 初始化目标,并将自己注册到该目标的观察者列表中  

     */  

    public BigBenClock(ClockTimerSubject subject){  

        this.subject = subject;  

        this.subject.attach(this);  

    }  

      

    /** 

     * 先检查发出通知的目标是否为自己注册过的,是则响应  

     */  

    @Override  

    public void update(ClockTimerSubject subject) {  

        if(this.subject == subject){  

            draw();  

        }  

    }  

  

    @Override  

    public void draw() {  

        System.out.println("伦敦大笨钟为您报时:"+subject.getTime());  

    }  

}  

/** 

 * 定时任务,每秒更新一次ClockTimerSubject的状态 

 */  

class TimerTask extends Thread{  

    private ClockTimerSubject timer;  

      

    public TimerTask(ClockTimerSubject timer){  

        this.timer = timer;  

    }  

  

    @Override  

    public void run() {  

        while(true){  

            try {  

                timer.tick();  

                Thread.sleep(1000);  

            } catch (InterruptedException e) {  

                e.printStackTrace();  

            }  

        }  

    }  

}  

运行结果:

[plain] view
plain copy

电子闹钟为您报时:2014-02-12 21:44:48  

伦敦大笨钟为您报时:2014-02-12 21:44:48  

电子闹钟为您报时:2014-02-12 21:44:49  

伦敦大笨钟为您报时:2014-02-12 21:44:49  

电子闹钟为您报时:2014-02-12 21:44:50  

伦敦大笨钟为您报时:2014-02-12 21:44:50  

电子闹钟为您报时:2014-02-12 21:44:51  

伦敦大笨钟为您报时:2014-02-12 21:44:51  

四、模式优缺点

优点:
1、目标和观察者间的抽象耦合。目标仅知道它有一系列符合抽象接口Observer的观察者,而不知道这些观察者属于哪个具体的类,这样目标和观察者之间的耦合就是抽象的和最小的。
2、支持广播通信。观察目标会向所有已注册的观察者对象发送通知,具体如何处理通知由观察者决定,简化了一对多系统的设计难度。
缺点:
1、意外的更新。由于观察者仅仅知道目标改变了,而不晓得具体什么被改变了,目标上的一个看似无害的操作可能会引起一系列对观察者及依赖于这些观察者的对象的更新,导致错误的产生。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: