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语法约束性较强,是强数据类型语言了,很多错编译阶段就会报错!


     

  • 相关阅读:
    洛谷 P1194 飞扬的小鸟 题解
    洛谷 P1197 星球大战 题解
    洛谷 P1879 玉米田Corn Fields 题解
    洛谷 P2796 Facer的程序 题解
    洛谷 P2398 GCD SUM 题解
    洛谷 P2051 中国象棋 题解
    洛谷 P1472 奶牛家谱 Cow Pedigrees 题解
    洛谷 P1004 方格取数 题解
    洛谷 P2331 最大子矩阵 题解
    洛谷 P1073 最优贸易 题解
  • 原文地址:https://www.cnblogs.com/dshvv/p/9932864.html
Copyright © 2011-2022 走看看