Java设计模式(17)——行为模式之观察者模式(Observer)

一、概述

  概念

  

   UML简图

  

   我们根据一个示例得类图来分析角色

  

  角色

  抽象主题:保存观察者聚集(集合),管理(增删)观察者

  抽象观察者:定义具体观察者的抽象接口,在得到主题通知后更新自己

  具体主题:将有关状态存入具体观察者,状态发生改变时,通知观察者

  具体观察者:存储与主题角色自洽的状态

二、实践

  我们先将上面的示例图使用Java代码实现,再讨论Java中的观察者

  抽象主题

/**
 * 抽象主题接口
 *
 * @author Administrator
 **/
public interface Subject {
    /**
     * 登记/增加一个观察者
     * @param observer 新增的观察者
     */
    void attach(Observer observer);

    /**
     *删除一个观察者
     * @param observer 删除的观察者
     */
    void detach(Observer observer);

    /**
     * 通知观察者
     */
    void notifyObserver();
}

  具体主题——可以注意复习我们之前学习的拉姆达表达式

/**
 * 具体主题角色
 *
 * @author Administrator
 **/
public class ConcreteSubject implements Subject{
    private List<Observer> observerList = new LinkedList<>();
    @Override
    public void attach(Observer observer) {
        observerList.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        observerList.remove(observer);
    }

    @Override
    public void notifyObserver() {
        // 遍历通知观察者(可以使用聚集的拷贝防止外部的修改)
        for (Observer observer : observerList) {
            observer.update();
        }
        // Java8写法
//        observerList.forEach((observer)-> observer.update());
//        observerList.forEach(Observer::update);
    }
}

  抽象观察者

/**
 * 观察者接口
 *
 * @author Administrator
 **/
public interface Observer {
    /**
     * 收到通知的更新操作
     */
    void update();
}

  具体观察者

/**
 * 具体观察者
 *
 * @author Administrator
 **/
public class ConcreteObserver implements Observer{
    @Override
    public void update() {
        // 更新的逻辑
    }
}

  当然,我们也可以改成第二种方案,将抽象主题改成抽象类,这样就可以由抽象角色来持有观察者的聚集引用,而且管理聚集的增删方法也可以直接在

抽象主题中直接实现,这样子类只需要很轻量级的代码了:

  

  有了上面的基础,我们来看Java对观察者的原生支持:

  Java的API还为为我们提供现成的Observer接口Java.util.Observer。我们只要直接使用它就可以。

  先看这个Observer接口:

  

  这个接口比较简单,我们直接看陌生的面孔——update()的参数类型:Observable,看它的介绍:

  

 

  

   看完文字的介绍我们也可以通过查看源码更加清晰的认识这个类

  接下来我们举一个栗子:假设一个商品的价格变更了应该通知它的观察者:——使用的是UML简图的方案二

  被观察者,产品:

/**
 * 具体被观察者
 *
 * @author Administrator
 **/
public class Product extends Observable{
    private String name;
    private float price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        // 设置通知
        setChanged();
        notifyObservers(name);
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
        setChanged();
        notifyObservers(new Float(price));
    }
}

  两个观察者:

/**
 * name观察者
 *
 * @author Administrator
 **/
public class NameObserver implements java.util.Observer{
    @Override
    public void update(Observable o, Object arg) {
        System.out.println(o);
        String name;
        if (arg instanceof String) {
            name = (String) arg;
            // 变更的逻辑
            System.out.println("产品名称已经变更为:" + name);
        }
    }
}

  

/**
 * price观察者
 *
 * @author Administrator
 **/
public class PriceObserver implements java.util.Observer{
    @Override
    public void update(Observable o, Object arg) {
        System.out.println(o);
        float price;
        if (arg instanceof Float) {
            // 变更逻的辑
            price = (Float) arg;
            System.out.println("产品价格变更为:" + price);
        }
    }
}

  客户端:

/**
 * 客户端
 * @author  Administrator
 **/
public class Client {
    public static void main(String[] args) {
        // 下面调用了新增的方法,无法使用多态声明
        Product product = new Product();
        java.util.Observer nameObserver = new NameObserver();
        java.util.Observer priceObserver = new PriceObserver();

        // 增加观察者
        product.addObserver(nameObserver);
        product.addObserver(priceObserver);

        product.setName("小西瓜");
        product.setPrice(100.1f);
    }
}

  

  // 这里第一个未使用到的参数就是抽象被观察者了,当然这里由于产品子类有新增方法,故不能调用新增方法

  而且,这里是通知了所有的观察者

posted @ 2017-10-31 14:42  ---江北  阅读(284)  评论(0编辑  收藏  举报
TOP