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

    先来领会一下观察者模式的精神:

    观察者模式定义了一系列对象之间一对多的关系。通俗的比喻相当于报社和订报的人,水电局和用户。也就是出版者和订阅者。

    观察者模式涉及到了如下几点定义:

      抽象主题角色

      具体主题角色

      抽象观察者角色

      具体观察者角色

    1.接下来是具体的例子

    就拿某直播平台的通知功能来说,其类图如下:(Tuhao就是土豪)

    假设游戏是一个大的主题,在这里它相当于一个抽象主题角色:

    public interface Game {
        void addPeople(People people);
    
        void removePeople(People people);
    
        void notifyPeople();
    }
    

    抽象主题角色最基本具有添加,移除以及通知观察者的功能

    然后是具体主题角色,例如在游戏分类下的StarCraft就是其中的一个游戏(具体主题角色):

    public class StarCraft implements Game {
    
        private ArrayList<People> viewer;
        private String message;
    
        public StarCraft() {
            viewer = new ArrayList<People>();
        }
    
        public void addPeople(People people) {
            viewer.add(people);
        }
    
        public void removePeople(People people) {
            if (viewer.contains(people)) {
                viewer.remove(people);
            } else {
                System.out.println("No viewers!");
            }
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    
        public void notifyPeople() {
            for (People people : viewer) {
                people.update(message);
            }
        }
    }

    它维护着该主题下的用户(观察者)列表,负责移除,添加观察者,发送通知等一系列操作。

    接下来就是抽象观察者角色了:

    public interface People {
        void update(String message);
    }
    

    最后就是具体观察者角色,例如上斗鱼看直播的土豪:

    public class Tuhao implements People {
        public void update(String message) {
            System.out.println("Watch: " + message+" and send money!");
        }
    }

    最后就是测试了:

    斗鱼某主播上开了直播,然后系统会通知订阅该直播的人直播开始了。

    测试:

        @Test
        public void test() {
            StarCraft starCraft = new StarCraft();
            starCraft.setMessage("干死黄旭东!");
            //土豪mike
            Tuhao mike = new Tuhao();
            starCraft.addPeople(mike);
            starCraft.notifyPeople();
        }
    //Watch: 干死黄旭东! and send money!

    2.在Java JDK中,自带有java.util.Observable以及Observer分别为抽象主题角色以及抽象观察者角色。

    使用它们改写观察者的关系如下:

    Observable默认使用Vector保存期观察者,且对其中的大部分方法都加了synchronized进行同步。不过,Observable是个类,继承了它就不能继承其他的类了。

    此外,还增加了changed标志,只有当changed标志为true的时候,通知才可进行,且通知完成后,会将标志重置为false:

    其代码如下:

    public class Observable {
        private boolean changed = false;
        private Vector<Observer> obs;
    
        public Observable() {
            obs = new Vector<>();
        }
    
        public synchronized void addObserver(Observer o) {
            if (o == null)
                throw new NullPointerException();
            if (!obs.contains(o)) {
                obs.addElement(o);
            }
        }
    
        public synchronized void deleteObserver(Observer o) {
            obs.removeElement(o);
        }
    
        public void notifyObservers() {
            notifyObservers(null);
        }
    
        public void notifyObservers(Object arg) {
            /*
             * a temporary array buffer, used as a snapshot of the state of
             * current Observers.
             */
            Object[] arrLocal;
    
            synchronized (this) {
               
                if (!changed)
                    return;
                arrLocal = obs.toArray();
                clearChanged();
            }
    
            for (int i = arrLocal.length-1; i>=0; i--)
                ((Observer)arrLocal[i]).update(this, arg);
        }
    
        public synchronized void deleteObservers() {
            obs.removeAllElements();
        }
    
        protected synchronized void setChanged() {
            changed = true;
        }
    
        protected synchronized void clearChanged() {
            changed = false;
        }
    
        public synchronized boolean hasChanged() {
            return changed;
        }
    
        public synchronized int countObservers() {
            return obs.size();
        }
    }

    具体主题:

    public class StarCraft extends Observable {
        public void setChanged(){//Observable的setChanged为protected,必须在主题实现中实现
            super.setChanged();
        }
    }
    

    具体观察者:

    public class Tuhao implements Observer{
        public void update(Observable o, Object arg) {
            System.out.println("土豪 online!");
            if(arg!=null){
                System.out.println(arg.toString());
            }
        }
    }
    

     测试:

        @Test
        public void test1(){
            StarCraft starCraft = new StarCraft();
            Tuhao mike = new Tuhao();
            starCraft.addObserver(mike);
            //可以查看状态是否改变
            boolean status = starCraft.hasChanged();
            System.out.println("状态是否改变:"+status);
            starCraft.notifyObservers();
            //可以查看共有多少待通知的对象
            System.out.println("将通知人数为:"+starCraft.countObservers());
            //改变状态,这里是重写了Observable的setChanged方法
            starCraft.setChanged();
            status = starCraft.hasChanged();
            System.out.println("状态是否改变:"+status);
            starCraft.notifyObservers();
            System.out.println("通知人数为:"+starCraft.countObservers());
            //通知完之后,状态会恢复原样,即为false,等待下一次需要状态的改变
            status = starCraft.hasChanged();
            System.out.println("状态是否改变:"+status);
        }
    //    状态是否改变:false
    //    将通知人数为:1
    //    状态是否改变:true
    //    土豪 online!
    //    通知人数为:1
    //    状态是否改变:false
    

     此外,还可以调用:

            starCraft.notifyObservers("额外信息");
    

    方法传递额外的信息。 

    3.最后,在Java GUI中,监听器的添加使用的就是观察者模式:

            JButton j = new JButton();
            j.addActionListener(new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    System.out.println("got it!");
                }
            });
    

    监听器的实现类(上面的匿名内部类)就是观察者,JButton就是主题。

    如上:)

    参考资料:

    Head First 设计模式

  • 相关阅读:
    ORA12560: TNS: 协议适配器错误
    eclipse无法识别Web项目的问题
    搭建eclipse+tomcat开发环境
    初探弹出层的实现原理
    样式可控的左右选择组件
    在TSQL中用队列来遍历层级数据
    复利计算工具 wpf
    浏览WPF中内置颜色名对应的颜色
    原创:通过VS 2010+SVN为SQL Server提供数据库版本管理
    原创:学习英语小助手(阅读粘贴的英文,使用MVVM)
  • 原文地址:https://www.cnblogs.com/zhangxd-stn/p/dp2.html
Copyright © 2011-2022 走看看