zoukankan      html  css  js  c++  java
  • 初探观察者模式

    观察者模式:定义了对象之间一对多的依赖,当一个对象改变状态时,他的所有依赖都会收到通知并自动更新。

    场景:有这样一个需求,风险监控的时候,某个用户关注了某个信息,并且希望这个信息有重大变动的时候能够往邮箱、手机、当前用户登录的网页发送这个信息。

    让我们来看看根据需求马上动手的代码:

    1、定义发送信息的类

    package pattern.observer;
    
    public class SendEmail {
        public void show(String message){
            System.out.println("您在XXX订阅的信息有更新,更新内容:" + message + "。该信息来自XXX邮箱");
        }
    }
    
    public class SendPhone {
        public void show(String message){
            System.out.println("您在XXX订阅的信息有更新,更新内容:"+message + "。该信息来自XXXX");
        }
    }
    
    public class SendWeb {
        public void show(String message){
            System.out.println("您订阅的信息有更新,更新内容:"+message);
        }
    }

    2、获取改变的信息并发送

    public void messageChange(String message){
            SendEmail sendEmail = new SendEmail();
            SendPhone sendPhone = new SendPhone();
            SendWeb sendWeb = new SendWeb();
    
            sendEmail.show(message);
            sendPhone.show(message);
            sendWeb.show(message);
        }

    我们来分析一下这样写代码的不足:首先,发送信息类里面的show()方法看起来像一个统一的接口,我们可以封装起来;其次,针对具体实现变成,这样会导致我们增加或删除一个发送通知的类时,我们必须要修改实现类。

    接下来,我们分析一下观察者模式是怎么实现对象一对多的情况的。

    首先实现主题接口和观察者接口

    package pattern.observer;
    
    public interface Subject {
        //注册观察者(就是发送信息的类)
        public void registerObserver(Observer observer);
        //删除观察者
        public void removeObserver(Observer observer);
        //通知观察者信息已经改变
        public void notifyObservers();
    }
    
    public interface Observer {
        //观察者接口,一旦信息有改变,执行更新操作
        public void update(String message);
    }

    然后信息实现主题(Object)接口

    package pattern.observer;
    
    import java.util.ArrayList;
    
    public class Message implements Subject{
        private String message;
        private ArrayList observers;
    
        public Message(){
            observers = new ArrayList();
        }
    
        //一旦信息符合要求,通知观察者更新信息
        public void messageChange(){
            if(message.equals("重大变化")){
                notifyObservers();
            }
        }
    
        //有信息进来就调用信息改变的方法
        public void setMessage(String message){
            this.message = message;
            messageChange();
        }
    
        @Override
        public void registerObserver(Observer observer) {
            observers.add(observer);
        }
    
        @Override
        public void removeObserver(Observer observer) {
            int i = observers.indexOf(observer);
            if(i>0){
                observers.remove(observer);
            }
        }
    
        @Override
        public void notifyObservers() {
            for(Object observer:observers){
                Observer o = (Observer)observer;
                o.update(message);
            }
        }
    }

    发送信息的类实现观察者(Observer)接口

    package pattern.observer;
    
    public class SendEmail implements Observer{
        private Subject subject;
    
        public SendEmail(Subject subject){
            this.subject = subject;
            subject.registerObserver(this);
        }
    
        public void show(String message){
            System.out.println("您在XXX订阅的信息有更新,更新内容:" + message + "。该信息来自XXX邮箱");
        }
    
        @Override
        public void update(String message) {
            show(message);
        }
    }
    
    public class SendPhone implements Observer{
        private Subject subject;
    
        public SendPhone(Subject subject){
            this.subject = subject;
            subject.registerObserver(this);
        }
    
        public void show(String message){
            System.out.println("您在XXX订阅的信息有更新,更新内容:"+message + "。该信息来自XXXX");
        }
    
        @Override
        public void update(String message) {
            show(message);
        }
    }
    
    public class SendWeb implements Observer{
        private Subject subject;
    
        public SendWeb(Subject subject){
            this.subject = subject;
            subject.registerObserver(this);
        }
    
        public void show(String message){
            System.out.println("您订阅的信息有更新,更新内容:"+message);
        }
    
        @Override
        public void update(String message) {
            show(message);
        }
    }

    最后实现控制器进行测试

    package pattern.observer;
    
    public class MessageController {
    
        public static void main(String[] args) {
            String messageStr = "重大变化";
            Message message = new Message();
            SendPhone sendPhone = new SendPhone(message);
            SendWeb sendWeb = new SendWeb(message);
            SendEmail sendEmail = new SendEmail(message);
    
            message.setMessage(messageStr);
        }
    
    }

    至此观察者模式完毕。


    其实还有个疑问,为什么要在观察者本身里面注册呢?

    public class SendEmail implements Observer{
        private Subject subject;
    
        public SendEmail(Subject subject){
            this.subject = subject;
            //为什么要在观察者保存Subject并且在初始化的时候用来注册
            subject.registerObserver(this);
        }
    
        public void show(String message){
            System.out.println("您在XXX订阅的信息有更新,更新内容:" + message + "。该信息来自XXX邮箱");
        }
    
        @Override
        public void update(String message) {
            show(message);
        }
    }

    是不是希望可以在观察者本身取消对消息的订阅?

    public class SendEmail implements Observer{
        private Subject subject;
    
        public SendEmail(Subject subject){
            this.subject = subject;
            this.subject.registerObserver(this);
        }
    
        public void show(String message){
            System.out.println("您在XXX订阅的信息有更新,更新内容:" + message + "。该信息来自XXX邮箱");
        }
    
        @Override
        public void update(String message) {
            show(message);
        }
    
        //取消订阅
        public void unsubscribe(){
            subject.removeObserver(this);
        }
    }
  • 相关阅读:
    火狐插件火狐黑客插件将Firefox变成黑客工具的七个插件
    memcache安装环境:WINDOWS 7
    PHP正则表达式
    968. 监控二叉树 力扣(困难) dfs 官方说DP
    375. 猜数字大小 II 力扣(中等) 区间动态规划、记忆化搜索
    629. K个逆序对数组 力扣(困难) 区间动态规划
    剑指 Offer 51. 数组中的逆序对 力扣(困难) 巧用归并排序算法
    488. 祖玛游戏 力扣(困难) dfs
    16. 最接近的三数之和 力扣(中等) 双指针
    319. 灯泡开关 力扣(中等) 数论
  • 原文地址:https://www.cnblogs.com/yzdtofly/p/9437511.html
Copyright © 2011-2022 走看看