• 设计模式--观察者(Observer)


    GOF给出的定义

    Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

    定义了对象之间的一种一对多的依赖关系,这样,当一个对象的状态发生变化时,所有的依赖对象都被通知并自动更新。

    包含观察者被观察者(也称为主题)

    使用场景

    1、有两个抽象类型相互依赖。将他们封装在各自的对象中,就可以对它们单独进行改变和复用。

    2、对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变。

    3、一个对象必须通知其他对象,而它又不需知道其他对象是什么。

    观察这模式的结构(UML)

    标准实现

    目标/被观察者(Subject) 在这里对观察者进行添加和删除操作,并通知观察者

     1 /**
     2  * 被观察者对象(目标/主题对象),注册和删除观察者的接口
     3  * 
     4  * @author blacksonny
     5  * @since 2015年7月1日
     6  */
     7 public class Subject {
     8 
     9     //保存注册的观察者对象
    10     private List<Observer> observers = new ArrayList<Observer>();
    11     
    12     //Attach observer
    13     public void attach(Observer o){
    14         observers.add(o);
    15     }
    16     
    17     //Delete observer
    18     public void detach(Observer o){
    19         observers.remove(o);
    20     }
    21     
    22     //Notify all observer who has register
    23     protected void notifyObservers(){
    24         for (Observer observer : observers) {
    25             observer.update(this);
    26         }
    27     }
    28 }

    观察者(Observer)  单目标对象发生变化时,通知这个对象

     1 /**
     2  * 观察者抽象接口,当目标对象发生改变时,通知这个对象
     3  * 
     4  * @author blacksonny
     5  * @since 2015年7月1日
     6  */
     7 public interface Observer {
     8 
     9     /**
    10      * 更新观察者
    11      * 
    12      * @param subject
    13      *            被观察者对象,方便获取被观察者状态
    14      */
    15     void update(Subject subject);
    16 }

    具体目标对象(ConcreteSubject)  继承Subject,在这里改变自身状态并通知观察者

     1 /**
     2  * 具体的被观察者对象
     3  * 
     4  * @author blacksonny
     5  * @since 2015年7月1日
     6  */
     7 public class ConcreteSubject extends Subject {
     8 
     9     // 被观察者对象的状态
    10     private String subjectState;
    11 
    12     public String getSubjectState() {
    13         return subjectState;
    14     }
    15 
    16     public void setSubjectState(String subjectState) {
    17         this.subjectState = subjectState;
    18         this.notifyObservers();//状态发生变化,通知观察者
    19     }
    20 
    21 }

    观察者实现(ConcreteObserver) 接收被观察者(目标对象)消息,两者状态保持一致

     1 /**
     2  * 具体的观察者对象,实现更新的方法,使自身的状态和被观察者对象状态保持一致
     3  * 
     4  * @author blacksonny
     5  * @since 2015年7月1日
     6  */
     7 public class ConcreteObserver implements Observer {
     8     // 观察者对象状态
     9     private String observerState;
    10 
    11     @Override
    12     public void update(Subject subject) {
    13         observerState = ((ConcreteSubject) subject).getSubjectState();
    14 
    15     }
    16 
    17 }

    JAVA自身提供的Observer模型

    SalaryConreteSubject被观察者实现,继承自JAVA提供的Observable被观察者
    观察者模式对消息的通知分为推、拉两种,推模式由subject发起,通知对象可以相对单一;拉模式由observer主动获取。拉模式就需要subject发送自身对象,而推模式可以是一个简单的数据类型,建议采用拉模式,易扩展。
    具体到代码中如下的标注的
    推方法主动传递一个消息内容 this.notifyObservers(salaryContent);
    拉方法则无需传递参数,默认传递this对象 this.notifyObservers();
     1 /**
     2  * 继承自jdk的被观察者
     3  * 
     4  * @author blacksonny
     5  * @since 2015年7月1日
     6  */
     7 public class SalaryConreteSubject extends Observable {
     8 
     9     private String salaryContent;
    10 
    11     public String getSalaryContent() {
    12         return salaryContent;
    13     }
    14 
    15     public void setSalaryContent(String salaryContent) {
    16         this.salaryContent = salaryContent;
    17         //必须调用
    18         this.setChanged();
    19         
    20         //推模式
    21         this.notifyObservers(salaryContent);
    22         
    23         //拉模式
    24         this.notifyObservers();
    25     }
    26 }
    Employee具体观察者, 实现Observer接口,并实现update方法,而其中的两个参数,第一个就是拉模式的参数,第二个为退模式参数
     1 /**
     2  * 实现java.util.Observer
     3  * 
     4  * @author blacksonny
     5  * @since 2015年7月1日
     6  */
     7 public class Employee implements Observer {
     8 
     9     @Override
    10     public void update(Observable o, Object arg) {
    11         System.out.println("本月发放工资情况 拉过来:" + ((SalaryConreteSubject) o).getSalaryContent());
    12         System.out.println("本月发放工资情况 推过来:" + arg);
    13     }
    14 }

    Client测试:

     1 /**
     2  * 测试java提供的观察者模式
     3  * 
     4  * @author blacksonny
     5  * @since 2015年7月1日
     6  */
     7 public class Client {
     8 
     9     /**
    10      * @param args
    11      */
    12     public static void main(String[] args) {
    13 
    14         // 创建被观察者对象
    15         SalaryConreteSubject subject = new SalaryConreteSubject();
    16 
    17         // 创建观察者对象
    18         Employee employee = new Employee();
    19         // 注册对象
    20         subject.addObserver(employee);
    21 
    22         subject.setSalaryContent("10k");
    23     }
    24 }

    输出结果

    本月发放工资情况 拉过来:10k
    本月发放工资情况 推过来:10k
  • 相关阅读:
    从零开始写代码AdaBoost算法的python实现
    从零开始写代码 ID3决策树Python
    redis有启动,但是其他主机telnet 不通的问题
    关于js查找和筛选和循环的几种方式(find();findIndex();filter();some();every();forEach;map();for/in)
    linux 设置tomcat 重启清空 catalina.out 断舍离
    旋转数组 断舍离
    nginx 普通用户启动配置 && springbootswagger 报错 Unable to infer base url 断舍离
    CentOS yum 直接安装最新的nginx【转】 断舍离
    买卖股票的最佳时机 II 断舍离
    swagger 的 pathmapping 配置的理解 断舍离
  • 原文地址:https://www.cnblogs.com/blacksonny/p/4609374.html
Copyright © 2020-2023  润新知