Java设计模式(5)之观察者模式学习总结

来源:互联网 发布:mac终端查询ip地址 编辑:程序博客网 时间:2024/06/05 06:07
    观察者模式:在观察者模式中,存在着对象之间的一对多的依赖关系,即一个对象的状态发生改变时,所有依赖于该对象的对象都会得到通知,并对自身的状态进行更新;    观察者模式的学习中,对象之间的一对多的依赖关系是学习观察者模式的切入点,而被依赖对象(目标对象)的状态改变会对依赖对象(观察者对象)状态产生影响是观察者模式的关键所在;只有对象之间形成一对多的依赖关系,才能实现被依赖对象与依赖对象之间的状态更新的交互作用;    生活中,其实存在很多观察者模式的应用场景,比如天气预报短信通知,当你在手机上开通了短信通知天气服务之后,每天你都会收到当天的天气信息的短信通知;再比如,你的手机上安装了腾讯体育APP,那么你只要接受该APP提供的推送即时消息通知的服务,那么一旦有更新的体育信息,将会向你的手机推送相关信息;    下面通过一个生活中的场景,进行相关的观察者模式设计代码:
    package com.pattern.observer;    import java.util.ArrayList;    import java.util.List;    /**     * 抽象目标类     * @author Administrator     */    public  class Subject {        //订阅者列表,用于存放订阅者对象        private List<Observer> list = new ArrayList<Observer>();        //添加订阅者        public void add(Observer o)         {            list.add(o);        }        //删除指定订阅者        public void delete(Observer o)        {            list.remove(o);        }        //通知所有订阅者        public void notifyAllObservers()         {            for (Observer observer : list)             {                //将目标对象传入观察者对象的update方法                observer.update(this);            }        }    }    package com.pattern.observer;    /**     * 具体目标类     * @author Administrator     */    public class WeatherSubject extends Subject {        //目标对象的状态信息        private String information;        public String getInformation()         {            return information;        }        //设置或更新目标状态信息        public void setInformation(String information)         {            this.information = information;            //更新状态信息后,调用通知方法,通知所有订阅者,使其进行各自的状态更新            this.notifyAllObservers();        }       }    package com.pattern.observer;    /**     * 观察者接口     * @author Administrator     */    public interface Observer {        //更新观察者状态        public abstract void update(Subject subject);    }    package com.pattern.observer;    /**     * 具体观察者类     * @author Administrator     */    public class ConcreteObserver implements Observer {        //观察者的名字        private String observerName;        //观察者的待更新状态信息        private String information;        //接收到信息后的响应信息        private String hint;        public ConcreteObserver(String name,String hint)         {            observerName = name;            this.hint = hint;        }        @Override        public void update(Subject subject)             information =((WeatherSubject)subject).getInformation();            System.out.println(observerName+"收到了"+information+"的通知"+","+hint);        }    }    package com.pattern.observer;    //测试类    public class TestObserverPattern {        public static void main(String[] args) {            //1.创建目标对象            WeatherSubject subject = new WeatherSubject();             //2.创建观察者对象            ConcreteObserver observerOne = new ConcreteObserver("Tom", "已收到,考虑是否去购物");            ConcreteObserver observerTwo = new ConcreteObserver("Jake", "已收到,考虑是否去旅游");            //3.添加观察者            subject.add(observerOne);            subject.add(observerTwo);            //4.更新目标状态信息            subject.setInformation("天气晴朗");        }    }
    在设计观察者模式的时候,由于对于向观察者对象传送的消息内容的不同,观察者模式又分为推模型和拉模型;    拉模型:将目标对象传给观察者对象,观察者对象需要目标对象的哪一部分的状态信息,就通过该目标对象获取信息;当观察者对象对更新信息的需求发生变化时,拉模型可以很好地应对变化的场景;在上述的例子中,采用的是拉模型进行观察者模型的设计;     推模型:将指定的更新信息通知给观察者对象,当观察者对更新信息有了不同的要求之后,这种方式将会显得难以适应变化的要求;    如果想将上述例子通过推模型实现,只需要对具体观察者类中的update进行修改和对具体目标类中的notifyAllObservers进行重写;修改如下:     public void notifyAllObservers()     {        for (Observer observer : list)         {            //将传入观察者对象的update方法            observer.update(information);        }    }    public void update(String information)     {        this.information = information;        System.out.println(observerName+"收到了"+information+"的通知"+","+hint);    }    在Java中,其实提供了观察者模式的实现,利用java.util包下的Observable类和Observer接口就可以大大简化我们自己设计观察者模式的步骤;利用Java提供的观察者模式的实现将上述例子重新进行设计:
    /**     *目标类的设计     */    package com.pattern.observerInJava;    import java.util.Observable;    public class ConcreteSubject extends Observable      {        private String weatherInfor;//天气信息        public String getWeatherInfor()         {            return weatherInfor;        }        public void setWeatherInfor(String weatherInfor)          {            this.weatherInfor = weatherInfor;            //使用Java提供的观察者模式,在进行通知观察者更新信息之前所必需的一步            this.setChanged();            //设置拉模型,将目标对象直接传到观察者方法中            this.notifyObservers();            //设置推模型,将具体需要通知的信息传到观察着方法中            this.notifyObservers(weatherInfor);        }       }    /**     *观察者类的设计     */    package com.pattern.observerInJava;    import java.util.Observable;    import java.util.Observer;    public class ConcreteObserver1 implements Observer     {        private String observerName;        private String weatherInfor;        public ConcreteObserver1(String name)         {            observerName = name;        }        @Override        public void update(Observable o, Object arg)          {            //采用拉模型进行观察者消息的更新            weatherInfor = ((ConcreteSubject)o).getWeatherInfor();            System.out.println(observerName+"从目标处拉取了更新的信息");            System.out.println(observerName+"收到了"+weatherInfor);            //采用推模型进行观察者消息的更新            System.out.println(observerName+"接收到了推动的更新的信息");            System.out.println(observerName+"收到了"+weatherInfor);        }    }    /**     *测试类的设计     */    package com.pattern.observerInJava;    import com.pattern.observerInJava.ConcreteObserver1;    public class TestObserverInJava    {        public static void main(String[] args)          {            //1.创建目标对象            ConcreteSubject subject = new ConcreteSubject();             //2.创建观察者对象            ConcreteObserver1 observerOne = new ConcreteObserver1("Tom");            ConcreteObserver1 observerTwo = new ConcreteObserver1("Jake");            //3.添加观察者            subject.addObserver(observerOne);            subject.addObserver(observerTwo);            //4.更新目标状态信息            subject.setWeatherInfor("天气晴朗");        }    }
    进一步地提出问题,当不同的观察者对象对目标对象的更新信息中感兴趣的方面不同,比如观察者对象A只对下雨天和阴天感兴趣,观察者对象B只对下雨天感兴趣,这时,将需要根据不同的需求向不同的观察者对象发送相应的更新信息;    这里可以使用面向接口编程的思想进行解决,设计一个抽象目标类,在该类中实现其具体实现类中公有的部分,而将notifyAllObservers方法放在其具体实现类中进行实现,在该方法中根据需求的不同进行不同的处理;    notifyAllObservers方法的具体实现可参考如下代码:    public void notifyAllObservers()     {        for (Observer observer : list)         {             //如果天气为下雨天,则只向观察者A、B推送更新信息            if("下雨天".equals(weatherInfor))            {                if(observer.getObserverName.equals("A"))                {                    observer.update(this);                }                if(observer.getObserverName.equals("B"))                {                    observer.update(this);                }            }            //如果天气为阴天,则指向观察者A推送更新信息            if("阴天".equals(weatherInfor))            {                if(observer.getObserverName.equals("A"))                {                    observer.update(this);                }            }        }    }    在当自己进行观察者模式设计的时候,这里给出一些适用于观察者模式设计的注意点:        ①命名上的建议:            目标接口定义为Subject            观察者接口定义为Observer            观察者接口中的的更新方法定义为update        ②触发通知的时机应该在更新完目标对象的状态信息之后通知        ③通知的顺序:观察者之间是平行的,在观察者模式中不需要指定通知的顺序     观察者模式设计流程分析:        准备阶段 1、创建目标对象 2、创建观察者对象 3、在目标对象中注册观察者对象        运行阶段 1、改变目标对象的状态 2、通知所有已注册观察者对象进行相应的处理 3、回调目标对象,获取相应数据    观察者优点及适用场景:    优点:    ①观察者模式实现了观察者和目标之间的抽象耦合;    ②观察者模式实现了动态联动;    ③观察者模式支持广播通信;    使用场景:    ①在一个业务场景中,某一方面的操作需要依赖另一方面状态的改变;    ②在更改一个对象的状态同时,需要连带着修改其他对象的状态,并且需要被连带修改的对象的个数不知道;    ③当需要实现通知对象和被通知对象之间的松散耦合的时候,选用观察者模式;
原创粉丝点击