zoukankan      html  css  js  c++  java
  • observer观察者模式

    观察者模式(有时又被称为发布-订阅Subscribe>模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己。

    观察者模式的组成

      抽象主题角色:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。

      抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。

      具体主题角色:在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。

      具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。通常用一个子类实现。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。

    下面是简单实现,为了好理解,这里不要抽象主题,直接写具体主题和观察者实现思路:

    1.观察者

    /**
     * 抽象观察者
     * @author 魅力_小生
     *
     */
    public interface Watcher {
        /**
         * 更新信息
         * @param obj 需要变更的内容
         */
        public void update(Object obj);
    }

    2.主题,也是被观察者

    /**
     * 主题,也是被观察者
     * 当主题变更时,通知观察者更新信息
     * @author 魅力_小生
     *
     */
    public abstract class Topic {
        //需要通知的观察者列表
        private List<Watcher> watcherList = new ArrayList<Watcher>();
    
        /**
         * 往观察者列表添加观察者
         * @param w
         */
        public void addWatcher(Watcher w){
            watcherList.add(w);
        }
        
        /**
         * 删除观察者列表中的观察者
         * @param w
         */
        public void removeWatcher(Watcher w){
            watcherList.remove(w);
        }
        
        /**
         * 通知观察者列表中的观察者,变更信息
         * @param updateContent 需要变更的内容
         */
        public void notifyWatcher(Object updateContent){
            for(Watcher w : watcherList){
                w.update(updateContent);
            }
        }
    }

    3.可以写多个观察者子类,然后添加到主题的观察者列表,当主题发生改变,调用notifyWatcher()去通知观察者进行变更。

    JDK的API的java.util包中已经封装了主题类Observable,和抽象观察者接口Observer,我们只需要继承它们就可以去应用我们的发布订阅模式了。

    应用实例:

    有一本图书《Java》,在价格发生改变时,去通知用户,给用户发Email和短信

    首先,被观察者类要去发送通知,接受变更后发Email和短信的类就是观察者了

    1.图书类Book

    public class Book
    {
        private String bookName = "Java";
        private float price = 40;//原价格
        public Book(String bookName, float price)
        {
            super();
            this.bookName = bookName;
            this.price = price;
        }
        public Book()
        {
        }
    
        public String getBookName()
        {
            return bookName;
        }
    
        public float getPrice()
        {
            return price;
        }
        @Override
        public String toString()
        {
            return "Book [bookName=" + bookName + ", price=" + price + "]";
        }
        
    }

    2.被观察者BookObservable继承java.util.Observable

    /**
     * 被观察者,继承Observable
     * 
     * 当价格变动时,通知各个观察者
     * @author  魅力_小生
     * @version  [版本号, 2016年2月26日]
     */
    public class BookObservable extends Observable
    {
        //图书价格变动,调用该方法,通知观察者
        public void noticeWatcher(Book book){
            //改变被观察者的状态
            super.setChanged();
            //当图书价格有变动,通知观察者
            super.notifyObservers(book);
        }
    
    }

    3.观察者类,接受通知,实现Observer接口

    /**
     * 观察者
     * 当图书价格变动,给用户发邮件
     * 
     * @author  魅力_小生
     * @version  [版本号, 2016年2月26日]
     */
    public class BookObserverEmail implements Observer
    {
    
        Book book = new Book();
        /**
         * Observable o:被观察的对象
         * Object arg:具体的业务对象
         */
        @Override
        public void update(Observable o, Object arg)
        {
            Book update = (Book)arg;
            System.out.println("Email:图书"+update.getBookName()+"降价了,现在价格是:"+update.getPrice());
            //收到通知,更新信息
            book = update;
        }
        
        public void printBookInfo(){
            System.out.println("Email的图书信息:"+book);
        }
        
    }
    /**
     * 观察者
     * 当图书价格变动,给用户发短信
     * 
     * @author  魅力_小生
     * @version  [版本号, 2016年2月26日]
     */
    public class BookObserverMobile implements Observer
    {
        
        Book book = new Book();
        /**
         * Observable o:被观察的对象
         * Object arg:具体的业务对象
         */
        @Override
        public void update(Observable o, Object arg)
        {
            Book update = (Book)arg;
            System.out.println("短信:图书"+update.getBookName()+"降价了,现在价格是:"+update.getPrice());
            //收到通知,更新信息
            book = update;
        }
        
        public void printBookInfo(){
            System.out.println("Mobile的图书信息:"+book);
        }
    }

    4.测试

    public static void main(String[] args)
        {
            Book book = new Book("Java", 36);//图书原来价格是40,降价为36
            //创建所有需要通知的观察者
            BookObserverEmail observerEmail = new BookObserverEmail();
            BookObserverMobile observerMobile = new BookObserverMobile();
            //创建被观察者
            BookObservable observable = new BookObservable();
            //被观察者中添加需要通知的观察者列表
            observable.addObserver(observerEmail);
            observable.addObserver(observerMobile);
            
            //调用通知方法,通知降价图书信息
            observable.noticeWatcher(book);
            
            //查看观察者更新后的图书信息
            System.out.println("---------------更新后的图书信息-----------------");
            observerEmail.printBookInfo();
            observerMobile.printBookInfo();
        }

    5.结果

    短信:图书Java降价了,现在价格是:36.0
    Email:图书Java降价了,现在价格是:36.0
    ---------------更新后的图书信息-----------------
    Email的图书信息:Book [bookName=Java, price=36.0]
    Mobile的图书信息:Book [bookName=Java, price=36.0]
    逃避不一定躲得过,面对不一定最难过
  • 相关阅读:
    NullPointerException
    面试oracle 经常问的一个问题- 事务
    python 之 import、from、as 关键字的 白话 解释与例子
    python 学习 之 第二章(条件、循环和其他语句)
    python学习 之 第一章 (简单例子与常用数据类型)
    python中常用函数含义记录
    python 2 版本中的input() 和 raw_input() 函数的比较
    字符串处理关键字str 和 repr
    文件操作-一个可以直接复制文件数据的小程序
    C语言 32个关键字
  • 原文地址:https://www.cnblogs.com/yangzhenlong/p/5222174.html
Copyright © 2011-2022 走看看