设计模式之观察者设计模式

388 阅读3分钟

定义

  • 观察者模式是行为型设计模式。
  • 对象订阅者与观察者之间存在一对多的关系,当订阅者对象发送改变时,观察者能感知这种变化做出相应的事件。

自定义代码实现

  • 这里用订阅者是店铺,观察者是两个喜欢苹果和华为的用户。通过店铺不同进货的产品,用户产生不同的响应事件。
  • 创建一个订阅者对象。
/**
 * 订阅者对象
 *
 * @author ZRH
 */
public class AppleShop {

    /**
     * 订阅者对象内容
     */
    private String apple = "还没有商品。。。";
    
    /**
     * 观察组
     */
    private List<UserBuy> list;

    /**
     * 初始化观察组对象容器
     */
    public AppleShop() {
        list = Lists.newArrayList();
    }

    /**
     * 进货苹果,并通知已订阅的观察者
     *
     * @param apple
     */
    public void setApple(String apple) {
        this.apple = apple;
        info();
    }

    /**
     * 获取订阅者对象内容
     *
     * @return
     */
    public String getApple() {
        return this.apple;
    }

    /**
     * 观察者注册到容器
     *
     * @param userBuy
     */
    public void setUserBuy(UserBuy userBuy) {
        this.list.add(userBuy);
    }

    /**
     * 通知观察者
     */
    public void info() {
        list.forEach(o -> o.buyApple());
    }
}
  • 定义观察者接口和观察者实现
 /**
 * 观察者接口,所有观察者都要实现当前接口,聚合对象。
 */
public interface UserBuy {

    /**
     * 声明观察者事件
     */
    void buyApple();
}
/**
 * 观察者 US
 *
 * @author ZRH
 */
public class UsUser implements UserBuy {

    /**
     * 订阅者对象
     */
    private AppleShop appleShop;

    public UsUser(AppleShop appleShop) {
        this.appleShop = appleShop;
    }

    @Override
    public void buyApple() {
        if ("苹果".equals(appleShop.getApple())) {
            System.err.println("我是UsUser 店铺有苹果了,我喜欢。。。");
        } else {
            System.err.println("我是UsUser 店铺没有苹果,我不买。。。");
        }
    }
}
/**
 * 观察者 China
 *
 * @author ZRH
 */
public class ChinaUser implements UserBuy {
    
    /**
     * 订阅者对象
     */
    private AppleShop appleShop;

    public ChinaUser(AppleShop appleShop) {
        super();
        this.appleShop = appleShop;
    }

    @Override
    public void buyApple() {
        if ("华为".equals(appleShop.getApple())) {
            System.err.println("我是ChinaUser 店铺有华为了,我喜欢。。。");
        } else {
            System.err.println("我是ChinaUser 店铺没有华为,我不买。。。");
        }
    }
}
  • 测试结果
/**
 * 测试类
 *
 * @author ZRH
 */
public class TestObserved {

    public static void main(String[] args) {
        shopObserved();
    }

    private static void shopObserved() {

        // 创建订阅者
        AppleShop appleShop = new AppleShop();

        // 创建观察者组
        UserBuy usUser = new UsUser(appleShop);
        UserBuy chainUser = new ChinaUser(appleShop);

        // 把观察者注册到订阅者中
        appleShop.setUserBuy(usUser);
        appleShop.setUserBuy(chainUser);

        // 获取控制台输入,模拟进货
        while (true) {
            Scanner scanner = new Scanner(System.in);
            appleShop.setApple(scanner.nextLine());
        }
    }
}

在这里插入图片描述

使用spring自带的观察者模式实现

  • 在spring的核心板rt.jar里有可以帮助我们事件观察者模式的类和接口。 在这里插入图片描述
  • 我们只需要继承订阅者类和实现观察者接口即可完成该设计模式的编写。
/**
 * 订阅者
 *
 * @author ZRH
 */
public class Subscription extends Observable {

    /**
     * 构造观察者容器
     */
    public Subscription() {
        super();
    }

    /**
     * 观察者注册到订阅者
     *
     * @param o
     */
    @Override
    public void addObserver(Observer o) {
        super.addObserver(o);
    }

    /**
     * 删除观察者
     *
     * @param o
     */
    public void deleteObserver(ObservedU o) {
        super.deleteObserver(o);
    }

    /**
     * 触发事件
     */
    @Override
    public void notifyObservers() {
        // 用于标记此对象已经被更改,必须调用此方法,否则无法通知观察者已经修改。
        super.setChanged();
        // 通知观察者触发
        super.notifyObservers();
    }
}
/**
 * 观察者 U
 *
 * @author ZRH
 */
public class ObservedU implements Observer {

    /**
     * 把当前观察者添加到订阅者容器内
     *
     * @param subscription
     */
    public ObservedU(Subscription subscription) {
        subscription.addObserver(this);
    }

    /**
     * 通知事件
     *
     * @param o   订阅者对象
     * @param arg 通知参数
     */
    @Override
    public void update(Observable o, Object arg) {
        if ("苹果".equals(arg)) {
            System.err.println("我是观察者U 店铺有苹果了,我喜欢。。。");
        } else {
            System.err.println("我是观察者U 店铺没有苹果,我不买。。。");
        }
    }
}
/**
 * 观察者 C
 *
 * @author ZRH
 */
public class ObservedC implements Observer {

    /**
     * 把当前观察者添加到订阅者容器内
     *
     * @param subscription
     */
    public ObservedC(Subscription subscription) {
        subscription.addObserver(this);
    }

    /**
     * 通知事件
     *
     * @param o   订阅者对象
     * @param arg 通知参数
     */
    @Override
    public void update(Observable o, Object arg) {
        if ("华为".equals(arg)) {
            System.err.println("我是观察者C 店铺有华为了,我喜欢。。。");
        } else {
            System.err.println("我是观察者C 店铺没有华为,我不买。。。");
        }
    }
}
  • 测试结果
/**
 * 测试类
 *
 * @author ZRH
 */
public class TestObserved {

    public static void main(String[] args) {
//         使用spring自带的观察者模式实现
        observed();
    }

    private static void observed() {

        // 创建订阅者
        Subscription subscription = new Subscription();

        // new二个观察者到订阅者容器里
        new ObservedU(subscription);
        new ObservedC(subscription);

        // 获取控制台输入,模拟进货
        while (true) {
            Scanner scanner = new Scanner(System.in);
            // 通知观察者触发
            subscription.notifyObservers(scanner.nextLine());
        }
    }

在这里插入图片描述

实际使用场景

  • 在java.util.EventListener和javax.servlet.http.HttpSessionBindingListener和 javax.servlet.http.HttpSessionAttributeListener等等都有观察者设计模式的应用。
  • 减低对象间的耦合度,改变订阅者或观察者对其他没有影响。
  • 以上代码demo主要是用于展示观察者设计模式的基本原理,在项目中的使用还需根据实际场景和业务需求进行完善和改动。
  • 最后虚心学习,共同进步 -_-