zoukankan      html  css  js  c++  java
  • 设计模式之观察者模式(Observer Pattern)

    一.什么是观察者模式?

    把现实世界中的报纸与订阅者的关系抽象出来就是观察者模式,一种报纸对应多个订阅者,订阅者可以随时解除订阅,未订阅的读者也可以随时开始订阅。一旦有新报纸发布,所有的订阅者都会收到新内容。

    在观察者模式中,报纸叫做主题Subject,订阅者叫做观察者Observer,一个Subject可以被多个Observer关注,Observer可以随时解除关注,新的Observer也可以随时关注Subject。Subject内容发生改变时,会通知所有的Observer。

    二.举个例子

    很多网络游戏中都有答题活动,所有参与答题活动的玩家都会同时收到题目信息(延迟忽略不计),未参与活动的玩家可以中途加入,正在答题的玩家也可以随时退出。

    在此例中,游戏服务器就是“一”,玩家是“多”,题目信息就是在它们之间传递的消息。

    怎样才能设计出满足以上要求的类?不妨试试观察者模式。

    首先,定义Subject抽象类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    package ObserverPattern;
     
    import java.util.ArrayList;
     
    /**
     * @author ayqy
     * 定义Subject抽象类
     *
     */
    public abstract class Subject {
        ArrayList<Observer> observers = new ArrayList<Observer>();//观察者列表
         
        /**
         * 注册主题
         * @param o 申请注册该主题的Observer
         */
        public void registSubject(Observer o)
        {
            observers.add(o);
        }
         
        /**
         * 删除主题
         * @param o
         */
        public void reomveSubject(Observer o)
        {
            int index = observers.indexOf(o);
            observers.remove(index);
        }
         
        /**
         * 通知所有观察者
         * @param arg 该Subject想要传递给Observers的数据
         */
        public void notifyObservers(Object arg)
        {
            for(Observer o : observers)
                o.update(this, arg);
        }
    }

    注意,这里用了抽象类而没有用接口,为什么?

    因为Subject的行为是fixed的,并不需要由子类来扩展。

    -------

    类似的,我们定义Observer抽象类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    package ObserverPattern;
     
    /**
     * @author ayqy
     * 定义Observer抽象类
     *
     */
    public abstract class Observer {
        Subject subject = null;//定义该Observer所关注的Subject
         
        public abstract void update(Subject subject, Object arg);//定义Observer的更新接口
    }

    -------

    下面开始实现我们的自定义Subject——GameServer:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package ObserverPattern;
     
    /**
     * @author ayqy
     * 定义GameServer类,继承自Subject基类,负责发布题目
     *
     */
    public class GameServer extends Subject{
        Question ques;//定义题目
     
        public Question getQues() {
            return ques;
        }
     
        public void setQues(Question q) {
            this.ques = q;
             
            super.notifyObservers(ques);//调用父类方法通知所有Observer
        }
    }

    P.S.GameServer类的成员变量Question是对题目信息的简单封装,Question类包含题号no与题目内容content两部分定义,以及一个toString方法,返回题目描述信息

    -------

    再实现我们的自定义Observer——Player:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package ObserverPattern;
     
    /**
     * @author ayqy
     * 定义PlayerA,继承自Observer基类,负责接收新题目
     *
     */
    public class PlayerA extends Observer{
         
        public PlayerA(Subject sub)
        {
            subject = sub;
        }
     
        @Override
        public void update(Subject subject, Object arg) {
            Question q = (Question)arg;
            System.out.println("PlayerA received " + q.toString());
        }
         
    }

    P.S.为了使类层次更加清晰,此处并没有定义Player基类

    很容易复制粘贴得到PlayerB与PlayerC,不再赘述

    至此,我们的模拟答题活动准备工作已经结束了,下面我们需要定义一个测试类来展示观察者模式的魅力。

    三.效果示例

    定义如下Test类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    package ObserverPattern;
     
    /**
     * @author ayqy
     * 实现一个测试类,模拟网络游戏答题活动(游戏服务器按时更新题目信息并通知所有参与答题的玩家)
     *
     */
    public class Test {
        public static void main(String[] args)
        {
            System.out.println("答题活动即将开始。。");
            //创建服务器
            GameServer gs = new GameServer();
            //创建玩家ABC
            Observer playerA = new PlayerA(gs);
            Observer playerB = new PlayerB(gs);
            Observer playerC = new PlayerC(gs);
            //为AB注册Subject,C对答题不感兴趣,拒绝注册
            gs.registSubject(playerA);
            gs.registSubject(playerB);
            System.out.println("玩家AB成功参与答题活动。。");
            System.out.println("答题活动正式开始。。");
            gs.setQues(new Question(1, "第一题"));
            gs.setQues(new Question(2, "第二题"));
            System.out.println("玩家A不想玩了,退出答题活动。。");
            gs.reomveSubject(playerA);
            gs.setQues(new Question(3, "第三题"));
            System.out.println("玩家C想中途加入活动");
            gs.registSubject(playerC);
            gs.setQues(new Question(4, "第四题"));
            System.out.println("答题活动结束。。");
        }
    }

    结果示例:

    四.总结

    从上面的例子可以看出观察者模式的特点:

    1.利用观察者模式可以轻易地建立对象之间“一对多”的依赖关系

    2.利用观察者模式的机制可以很容易的实现这种依赖关系的动态维护

    <原创>黯羽轻扬 欢迎转载 不必注明原文出处</原创>
    <声明>作者水平有限 错误在所难免 欢迎指正</声明>
    <邮箱>835412398@qq.com 交流方可进步</邮箱>
  • 相关阅读:
    第五次作业
    第四次作业
    软件工程(第二次作业)
    读软件工程这本书的感悟(第一次作业)
    第五次作业
    软件工程第四次作业
    软件工程第二次作业
    软件工程第二次作业
    什么样的书叫做好书,大学的教育到底培养的是什么?
    软件工程学习的问题:
  • 原文地址:https://www.cnblogs.com/jiligalaer/p/3963819.html
Copyright © 2011-2022 走看看