Java 观察者模式

 本文作为学习记录,欢迎转载学习。

  首先说明一下,我也是参考了资料和各个大神的博客进行学习的,所以我这里只说说个人理解,如果有地方错误欢迎指出,希望共同学习共同进步。声明:个人理解部分可能会有明显错误,希望指出.

 这里先给出各个博客一般的开头部分:

在阎宏博士的《JAVA与模式》一书中开头是这样描述观察者(Observer)模式的:

观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

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

观察者模式的结构

  一个软件系统里面包含了各种对象,就像一片欣欣向荣的森林充满了各种生物一样。在一片森林中,各种生物彼此依赖和约束,形成一个个生物链。一种生物的状态变化会造成其他一些生物的相应行动,每一个生物都处于别的生物的互动之中。

  同样,一个软件系统常常要求在某一个对象的状态发生变化的时候,某些其他的对象做出相应的改变。做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合度的设计方案。减少对象之间的耦合有利于系统的复用,但是同时设计师需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作。观察者模式是满足这一要求的各种设计方案中最重要的一种。

  下面以一个简单的示意性实现为例,讨论观察者模式的结构。

  观察者模式所涉及的角色有:

  ●  抽象主题(Subject)角色:抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。

  ●  具体主题(ConcreteSubject)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。

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

  ●  具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态 像协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。

 个人理解: 上面的一大段的说明其实我第一次看比较愣逼,因为这些名词都有点太抽象了,虽然有对观察者角色的详细解释,但第一次接受起来还是很难理解的(不知道是不是博主比较笨还是知识储备太少或许都有吧),所以大概我就说明一下,上面那些是重点

      1.我们为什么要选择观察者模式?模式的优点或者说是为了解决某些时候的需求? 

     这个模式定义了 “一对多的依赖关系”  首先分析 “一对多” 然后“依赖关系” 这就是需求和为什么使用观察者模式。

      2.观察者和主题的关系?

     这时就是看上面的图来对模式进行大致的模型概念。

      3.图形上的类 对应的角色具体是指什么?

     再看上面的角色说明

     这是上文的重点,虽然有点多余,但还是抽出来说明一下,我是怎么查看文章的。

     最后我说明我看完上面的大致理解: 我把观察者模式看成了老师和学生  

                     老师指的是上文的“抽象主题角色”,

                     学生指的是上文的“抽象观察者角色”,

                     具体的某个班的 徐老师就是“具体主题角色”,

                     具体的某个班的 学生就是“具体观察者角色”

                     “一对多的依赖关系”的概念就是老师对多个学生的概念,

                     “主题对象在状态上发生变化时,会通知所有观察者对象”的概念就是学校教导处通知老师布置作业内容是“我有一个梦想”,老师需要去通知学生,班上所有的学生接受老师布置的作业(其实老师用来分发任务而已)。

                       这里只是提供了一个理解和记忆方式而不是说就应该这么理解这个模式。

     根据我的理解然后我们先来看看代码

1.新建抽象观察者角色(学生)

/**
 * 
 * 抽象观察者类 (学生)
 *
 */
public abstract class StudentObServer {

    /*更新观察者类的状态 更新作业 homework  */
    public abstract void update(String homework);
}

更新老师布置的作业 update()  这里我说明一下,好多博客都是先放的抽象主题角色类 也就是下面的代码,导致看下面的代码中的StudentObServer 不知道是什么,所以我就把它提到前面来写了.

2.新建抽象主题角色(老师)

/**
 * 抽象主题类(老师)
 * 
 */
public abstract class TeacherSubject {

    /** 观察者集合 **/
    private List<StudentObServer> list = new ArrayList<StudentObServer>();
    
    
    /**
     * 添加观察者(学生)
     * @param observer
     */
    public void add(StudentObServer observer){
        
        list.add(observer);
    }
    
    /**
     * 移除观察者 (学生)
     * @param observer
     */
    public void remove(StudentObServer observer){
        
        list.remove(observer);
    }
    
    /**
     * 通知所有注册的观察者(通知所有注册在本老师名下的学生)
     * @param newState
     */
    public void notifyObServer(String homework){
        
        for (StudentObServer obServer : list) {
            obServer.update(homework);
        }
    }
}

我们这里的通知是相当于老师布置作业,我们看当前类的参数 :

1. list 是观察者的集合,也就是当前老师所有学生的集合。

2. add remove 老师有不给这个学生布置作业的权力,也有添加新学生布置作业的权利。

3. notifyObServer 通知注册观察者也就是老师布置作业或者说通知学生。

3.新建具体主题角色(徐老师)继承抽象主题角色类

/**
 * 具体主题角色
 */
public class ExampleTeacherSubject extends Subject {

    private String homework;

    public String getHomework() {
        return homework;
    }
    
    /**
     * 主题状态发生变化 (布置作业)
     */
    public void change(String homework){
        
        this.homework= homework;
System.out.println("教导处发布的作业为:" + homework);
this.notifyObServer(homework); } }

 4.新建具体观察者角色(学生)继承抽象观察者角色类

/**
 * 
 *  具体观察者角色(某个具体学生)
 *
 */
public class ExampleStuObServer extends ObServer {

    /***
     * 观察者名称 学生名称
     */
    private String name;
    
    /**
     * 观察者编号 学生编号
     */
    private String number;
    
    public ExampleStuObServer (String name,String number){
        this.name = name;
        this.number = number;
    }
    
    @Override
    public void update(String homework) {

        System.out.println("学生"+name+"学号为"+ number +"作业内容为:  "+homework);
    }
}

 5.老师收到教导处布置的作业内容,执行通知自己班的学生

public class Main {

    /**
     * 程序入口
     * @param args
     */
    public static void main(String[] args) {

        //教导处发布的作业 
        private String homewok="我有一个梦想";
        //实例化具体主题角色对象徐老师
        ExampleTeacherSubject xuTeacher= new ExampleTeacherSubject();
        
        //创建观察者对象 学生zou 学生qun 学生zhu
        ExampleStuObServer stu1= new ExampleStuObServer ("zou", "01");
        ExampleStuObServer stu2= new ExampleStuObServer ("qun", "02");
        ExampleStuObServer stu3= new ExampleStuObServer ("zhu", "03");
        
        //注册观察者 将学生加入到徐老师下的班级
        xuTeacher.add(stu1);
        xuTeacher.add(stu2);
        xuTeacher.add(stu3);
        
        //教导处通知老师,老师会去通知自己班级下的学生
        xuTeacher.change(homework);
    }
}                            

 执行结果:

我的理解差不多就是这样,下面给出原来的代码。

1.新建抽象观察者角色

/**
 * 
 * 抽象观察者类
 * @author qlzou
 */
public abstract class ObServer {

    //更新观察者类的状态
    public abstract void update(String newState);
}

2.新建抽象主题角色

/**
 * 抽象主题类
 * 
 */
public abstract class Subject {

    /** 观察者集合 **/
    private List<ObServer> list = new ArrayList<ObServer>();
    
    
    /**
     * 添加观察者
     * @param observer
     */
    public void add(ObServer observer){
        
        list.add(observer);
    }
    
    /**
     * 移除观察者
     * @param observer
     */
    public void remove(ObServer observer){
        
        list.remove(observer);
    }
    
    /**
     * 通知所有注册的观察者
     * @param newState
     */
    public void notifyObServer(String newState){
        
        for (ObServer obServer : list) {
            obServer.update(newState);
        }
    }
}

3.新建具体主题角色

/**
 * 具体主题角色
 */
public class ExampleSubject extends Subject {

    private String state;

    public String getState() {
        return state;
    }
    
    /**
     * 主题状态发生变化
     */
    public void change(String newState){
        
        this.state = newState;
        
        System.out.println("具体主题角色状态为:" +newState);
        
        this.notifyObServer(newState);
    }
    
}

4.新建具体观察者角色

/**
 * 
 *  具体观察者角色
 *
 */
public class ExampleObServer extends ObServer {

    /***
     * 观察者名称
     */
    private String name;
    
    /**
     * 观察者编号
     */
    private String number;
    
    public ExampleObServer(String name,String number){
        this.name = name;
        this.number = number;
    }
    
    @Override
    public void update(String newState) {

        System.out.println("观察者"+name+"编号为"+ number +"状态为:  "+newState);
    }
}

5.程序入口

public class Main {

    /**
     * 程序入口
     * @param args
     */
    public static void main(String[] args) {

        //实例化具体主题角色对象
        ExampleSubject subject = new ExampleSubject();
        
        //创建观察者对象
        ExampleObServer obServer1 = new ExampleObServer("zou", "01");
        ExampleObServer obServer2 = new ExampleObServer("qun", "02");
        ExampleObServer obServer3 = new ExampleObServer("zhu", "03");
        
        //注册观察者
        subject.add(obServer1);
        subject.add(obServer2);
        subject.add(obServer3);
        
        //主题状态发生改变   观察者状态同步发生改变
        subject.change("我有一个梦想");
        
    }
}

这里给出个参考的博客:http://www.cnblogs.com/java-my-life/archive/2012/05/16/2502279.html  博主写的很详细值得一看

原文地址:https://www.cnblogs.com/woaixingxing/p/6393555.html