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

    观察者模式:在观察者模式中,存在着对象之间的一对多的依赖关系,即一个对象的状态发生改变时,所有依赖于该对象的对象都会得到通知,并对自身的状态进行更新;
    观察者模式的学习中,对象之间的一对多的依赖关系是学习观察者模式的切入点,而被依赖对象(目标对象)的状态改变会对依赖对象(观察者对象)状态产生影响是观察者模式的关键所在;只有对象之间形成一对多的依赖关系,才能实现被依赖对象与依赖对象之间的状态更新的交互作用;
    生活中,其实存在很多观察者模式的应用场景,比如天气预报短信通知,当你在手机上开通了短信通知天气服务之后,每天你都会收到当天的天气信息的短信通知;再比如,你的手机上安装了腾讯体育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、回调目标对象,获取相应数据

    观察者优点及适用场景:
    优点:
    ①观察者模式实现了观察者和目标之间的抽象耦合;
    ②观察者模式实现了动态联动;
    ③观察者模式支持广播通信;
    使用场景:
    ①在一个业务场景中,某一方面的操作需要依赖另一方面状态的改变;
    ②在更改一个对象的状态同时,需要连带着修改其他对象的状态,并且需要被连带修改的对象的个数不知道;
    ③当需要实现通知对象和被通知对象之间的松散耦合的时候,选用观察者模式;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值