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

    前提:
    在翻阅资料的时候,有人把观察者(Observer)模式等同于发布(Publish)/订阅(Subscribe)模式,也有人认为这两种模式还是存在差异,而我认为确实是存在差异的,本质上的区别是调度的地方不同。但是因为后者是前者发展变异而来,故而列到一篇博客中

    观察者模式
    比较概念的解释是,目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。具体观察者和具体目标继承各自的基类,然后具体观察者把自己注册到具体目标里,在具体目标发生变化时候,调度观察者的更新方法。

    因为前端语言纷繁复杂,下边我分别举出es5、es6、ts版本

    ts版本

    /***
     * 抽象被观察者接口
     * 声明了添加、删除、通知观察者方法
     */
    public interface Observerable {
        registerObserver(o:Observer);
        removeObserver(o:Observer):;
        notifyObserver();
    }
    
    /***
     * 抽象观察者
     * 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。
     */
    public interface Observer {
        update( message:string);
    }
    
    
    
    /**
     * 被观察者,也就是微信公众号服务
     * 实现了Observerable接口,对Observerable接口的三个方法进行了具体实现
     */
    public class WechatServer implements Observerable {
        private list:Observer[];
        private message:string;
        constructor(){
            this.list = [];
        }
        public registerObserver(o: Observer) {
            this.list.push(o)
        }
        public removeObserver(o: Observer) {
            for (var i=0; i < this.list.length; i++){
                if (this.list[i] === o){
                    this.list.splice(i, 1);
                    break;
                }
            }
        }
        public notifyObserver() {
            for(let i = 0; i < this.list.length; i++) {
                let oserver = this.list[i];
                oserver.update(this.message);
            }
        }
        public setInfomation(s:string) {
            this.message = s;
            console.log(`微信服务更新消息:${s}`);
            //消息更新,通知所有观察者
            this.notifyObserver();
        }
    }
    
    
    /**
     * 观察者
     */
    public class User implements Observer {
        private  name:string;
        private  message:string;
        constructor(name:string) {
            this.name = name;
        }
        public update(message:string) {
            this.message = message;
            this.read();
        }
        public read() {
            console.log(`${this.name}收到推送消息:${this.message}`);
        }
    }
    
    
    /**
     * 我们来测试
     */
    let server = new WechatServer();
    let userZhang = new User("张三");
    let userLi = new User("李四");
    let userWang = new User("王五");
    server.registerObserver(userZhang);
    server.registerObserver(userLi);
    server.registerObserver(userWang);
    server.setInfomation("PHP是世界上最好用的语言!");
    console.log("-----用户张三看到消息后颇为震惊,果断取消订阅,这时公众号又推送了一条消息,此时用户ZhangSan已经收不到消息,其他用户还是正常能收到推送消息----------------");
    server.removeObserver(userZhang);
    server.setInfomation("JAVA是世界上最好用的语言!");
    
    
    
    /**
     * 总结:这个是ts去写的,因为用js写,我觉得理解起来很费劲,哪怕是es2018!编译后可能就是你想要的版本吧
     * 这个模式是典型的观察者模式,而非变异后的发布-订阅模式,两者有关联,但是并不一样
     * 其实前边两个接口是可以不用定义的,但是接口就是用来做规范的,以后可能不只有微信服务,还有新闻订阅、小程序订阅、iphoneXR订购等等
     * 这个模式是松偶合的。改变主题或观察者中的一方,另一方不会受到影像
     * 参考自java设计模式:https://www.cnblogs.com/luohanguo/p/7825656.html
     */
    View Code

    es5版本
    写完之后,突然发现,这尼玛不就是ts编译后的代码嘛,那两个抽象类的作用仅仅用在编译阶段,编译后的代码并不存在相关接口代码,哦!原来ts是这么个机制

    /**
     * 被观察者,也就是微信公众号服务
     */
    var WechatServer = (function () {
        function WechatServer() {
            this.list = [];
        }
        WechatServer.prototype.registerObserver = function (o) {
            this.list.push(o);
        };
        WechatServer.prototype.removeObserver = function (o) {
            for (var i = 0; i < this.list.length; i++) {
                if (this.list[i] === o) {
                    this.list.splice(i, 1);
                    break;
                }
            }
        };
        WechatServer.prototype.notifyObserver = function () {
            for (var i = 0; i < this.list.length; i++) {
                var oserver = this.list[i];
                oserver.update(this.message);
            }
        };
        WechatServer.prototype.setInfomation = function (s) {
            this.message = s;
            console.log(`微信服务更新消息:${s}`);
            //消息更新,通知所有观察者
            this.notifyObserver();
        };
        return WechatServer;
    }());
    
    
    /**
     * 观察者
     */
    var User = (function () {
        function User(name) {
            this.name = name;
        }
        User.prototype.update = function (message) {
            this.message = message;
            this.read();
        };
        User.prototype.read = function () {
            console.log(`${this.name}收到推送消息:${this.message}`);
        };
        return User;
    }());
    
    
    
    /**
     * 我们来测试
     */
    let server = new WechatServer();
    let userZhang = new User("张三");
    let userLi = new User("李四");
    let userWang = new User("王五");
    server.registerObserver(userZhang);
    server.registerObserver(userLi);
    server.registerObserver(userWang);
    server.setInfomation("PHP是世界上最好用的语言!");
    console.log("-----用户张三看到消息后颇为震惊,果断取消订阅,这时公众号又推送了一条消息,此时用户ZhangSan已经收不到消息,其他用户还是正常能收到推送消息----------------");
    server.removeObserver(userZhang);
    server.setInfomation("JAVA是世界上最好用的语言!");
    View Code

    es6版本
    通过这个可以了解到,因为目前包括es2018尚未实现接口、抽象功能,故而无法定义观察者约束性接口,然后还知道了,es6只是语法糖,类似于ts一样,创建类,其实本质就是es5 混合继承知识点:属性用构造,公共函数放在原型对象上,这样所有实例在内存共享一个方法,节省内存,说远了,哈哈不说了,贴代码

    /**
     * 被观察者,也就是微信公众号服务
     */
    class WechatServer{
        constructor(){
            this.list = [];
        }
        registerObserver(o) {
            this.list.push(o);
        };
        removeObserver(o){
            for (var i = 0; i < this.list.length; i++) {
                if (this.list[i] === o) {
                    this.list.splice(i, 1);
                    break;
                }
            }
        }
        notifyObserver() {
            for (var i = 0; i < this.list.length; i++) {
                var oserver = this.list[i];
                oserver.update(this.message);
            }
        }
        setInfomation(s){
            this.message = s;
            console.log(`微信服务更新消息:${s}`);
            //消息更新,通知所有观察者
            this.notifyObserver();
        }
    }
    
    /**
     * 观察者
     */
    class User{
        constructor(name) {
            this.name = name;
        }
        update(message) {
            this.message = message;
            this.read();
        };
        read (){
            console.log(`${this.name}收到推送消息:${this.message}`);
        };
    };
    
    /**
     * 我们来测试
     */
    let server = new WechatServer();
    let userZhang = new User("张三");
    let userLi = new User("李四");
    let userWang = new User("王五");
    server.registerObserver(userZhang);
    server.registerObserver(userLi);
    server.registerObserver(userWang);
    server.setInfomation("PHP是世界上最好用的语言!");
    console.log("-----用户张三看到消息后颇为震惊,果断取消订阅,这时公众号又推送了一条消息,此时用户ZhangSan已经收不到消息,其他用户还是正常能收到推送消息----------------");
    server.removeObserver(userZhang);
    server.setInfomation("JAVA是世界上最好用的语言!");
    View Code

    最后再想哔哔两句:
    ts和es6都是语法糖,所以面试的人会问你编译之后会是啥样,挺操dan的,因为java从来不会问我编译后的字节码是什么样
    ts跟es6比,就拿这个来说,可以使用接口来约束观察者,防止程序员乱写,可以用数据类型来约束各种参数和返回值,防止乱传,等到了运行再报错,代码我都写了几千行了,谁tm找得到啊。大体来说ts语法约束性较强,是强数据类型语言了,很多错编译阶段就会报错!


     

  • 相关阅读:
    FFMPEG 中dts和pts区别
    time_base
    [总结]FFMPEG视音频编解码零基础学习方法
    autolayout收集,适配,自动布局 状态栏 applicationFrame
    滑出式导航面板
    WPF与WCF c#
    App Icons on iPad and iPhone UI 尺寸
    mac iPhone管理工具
    scrollview背景
    网络编程链接
  • 原文地址:https://www.cnblogs.com/dshvv/p/9932864.html
Copyright © 2011-2022 走看看