观察者模式实现非直接耦合

吾粲
• 阅读 4095

最近在看设计模式,一本《Head First 设计模式》,一本《javascript设计模式》,两本交替着看。Head First浅显易懂,代码用java实现,理解了一个设计模式的理念以后,先想想用js如何实现,然后再看js设计模式相关章节,感觉比以前看的时候理解深入了些。

今天早上看到颜海镜同学在早读课上分享的耦合关系一文,最后一种模块间非直接耦合的实现方式第一个让我想到的就是观察者模式。正好上午没事,就写了个demo实现了一下。

非直接耦合:两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的。耦合度最弱,模块独立性最强。子模块无需知道对方的存在,子模块之间的联系,全部变成子模块和主模块之间的联系。

观察者模式实现非直接耦合

现在要实现这样的功能:

  1. 所有模块只和主模块通讯,可以把自己的变化告知主模块,也可以从主模块接受信息并处理;

  2. 主模块负责监听所有其下的模块的变化,一旦认为该变化需要通知到指定一个或多个其他模块,就向这些模块发送消息。

大体实现思路是:

子模块包含一个主模块的引用,在实例化方法中将其对应的主模块实例作为参数赋值给自己的主模块引用。

constructor(hub) {
    this._hub = hub;
}
    

子模块统一实现监听方法observeFromHub,供主模块触发执行自己的观察方法,具体由子类实现。

observeFromHub() {
    throw new Error('no implementation.');
}

子模块统一实现将自己的变化告知主模块的方法update(value)

update(value){
    this._hub.observeFromModule(value);
}

主模块包含一个子模块列表

constructor(){
    this.modules = [];
}

子模块统一实现add/remove方法,将自己添加到主模块的子模块列表modules中。

add(hub) {
    var alreadyExists = hub.modules.some((el)=>el === this);
    if (!alreadyExists) hub.modules.push(this);
    return this;
}

remove(hub) {
    hub.modules = hub.modules.filter((el)=>el !== this);
    return this;
}

主模块实现触发子模块列表中所有子模块的监听方法。

deliver(data){
    this.modules.forEach((module) => module.observeFromHub(data));
    return this;
}

主模块实现监听方法observeFromModule,供子模块触发执行自己的观察方法,由此来感知子模块的变化,进而执行deliver方法通知其下所有子模块。

observeFromModule(data) {
    return this.deliver(data);
}

有些方法子模块是公用的,所以可以将这些公共方法提取出来作为子模块的抽象超类

CommonModule.js

module.exports = class CommonModule {
    constructor(hub) {
        this._hub = hub;
    }
    
    update(value){
        this._hub.observeFromModule(value);
    }

    observeFromHub() {
        throw new Error('no implementation.');
    }

    add(hub) {
        var alreadyExists = hub.modules.some((el)=>el === this);
        if (!alreadyExists) hub.modules.push(this);
        return this;
    }

    remove(hub) {
        hub.modules = hub.modules.filter((el)=>el !== this);
        return this;
    }
}

observeFromHub方法有子模块自己实现。这里创建两个子模块Module1和Module2。当修改Module1时,主模块通知Module2执行observerFromHub(value)方法:

Module1.js

var CommonModule = require('./CommonModule');
module.exports = class Module1 extends CommonModule{
    constructor(hub) {
        super(hub);
        this.inputValue = '';
    }

    update(value) {
        this.inputValue = value;
        console.log('module1 setInput start... :' + this.inputValue);
        super.update(value);
    }
}

Module2.js

var CommonModule = require('./CommonModule');
module.exports = class Module2 extends CommonModule{
    constructor(hub) {
        super(hub);
        this.outputValue = '';
    }

    observeFromHub(value) {
        this.outputValue = value;
        console.log('module2 received msg : ' + this.outputValue);
    }
}

主模块代码:

Hub.js

module.exports = class Hub {
    constructor(){
        this.modules = [];
    }

    observeFromModule(data) {
        return this.deliver(data);
    }
    
    deliver(data){
        this.modules.forEach((module) => module.observeFromHub(data));
        return this;
    }
}

客户端代码:

main.js

var Hub = require('./Hub');
var Module1 = require('./Module1');
var Module2 = require('./Module2');

var hub = new Hub;
var inputModule = new Module1(hub);
var outputModule = new Module2(hub);

outputModule.add(hub);

inputModule.update('this is m1 speaking...');

执行main.js结果:

module1 setInput start... :this is m1 speaking...
module2 received msg : this is m1 speaking...

这个例子中主模块既是观察者,观察ModuleA的变化,又是被观察者,被ModuleB观察着,A一有变化就会将信息发送给B。

还能想到的一些有趣变化:

  1. 主模块可以有多个,各自管辖的范围不同,但有些子模块可能会在多个范围中公用。

  2. 主模块中添加控制器,数据需不需要下发,下发到那几个子模块,由主模块控制。

点赞
收藏
评论区
推荐文章
徐小夕 徐小夕
4年前
《前端实战总结》之使用解释器模式实现获取元素Xpath路径的算法
前端领域里基于javascript的设计模式和算法有很多,在很多复杂应用中也扮演着很重要的角色,接下来就介绍一下javascript设计模式中的解释器模式,并用它来实现一个获取元素Xpath路径的算法。上期回顾《前端实战总结》之迭代器模式的N1种应用场景(https://juejin.im/post/6844904008616771591)
3A网络 3A网络
3年前
Golang 常见设计模式之单例模式
之前我们已经看过了Golang常见设计模式中的装饰和选项模式,今天要看的是Golang设计模式里最简单的单例模式。单例模式的作用是确保无论对象被实例化多少次,全局都只有一个实例存在。根据这一特性,我们可以将其应用到全局唯一性配置、数据库连接对象、文件访问对象等。Go语言实现单例模式的方法有很多种,下面我们就一起来看一下。饿汉式饿汉式实现单例模式非
Wesley13 Wesley13
3年前
java设计模式详细讲解
原文链接:java设计模式详细讲解观察者模式(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fwww.blogchina.cn%2Fblog%2Fguopengfei%2Fhome%2F270%2F1575725711626"java设计模式详细讲解观察者模式")如果想要更加
Wesley13 Wesley13
3年前
java之设计模式
看了设计模式,感觉自己很多不理解什么意思,通过看博客别人写的理解,总结了一下,方便查阅。一、设计模式六大原则1、单一职责原则:定义:应该有且只有一个原因引起类的变化。注意:这里的类不光指类,也适用于方法和接口,比如我们常说的一个方法实现一个功能。2、开放封闭原则:定义:类、模块、函数等
Wesley13 Wesley13
3年前
java24种设计模式
一、设计模式定义  设计模式(DesignPattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。二、设计模式分类  经典模式只有23个(还有简单工厂模式),它们各具特色,每个模式都为某一个可重复的设计问题提供了一套解决方案。  根据它们的用
架构师日记-深入理解软件设计模式 | 京东云技术团队
本文从设计模式与编程语言的关系,设计模式与架构模式的区别,设计原则和设计模式的关系等几个维度进行了分析和解答。关于设计模式应该如何学习和应用的问题,给出了学习意见和实践心得。
海军 海军
4年前
JavaScript设计模式之单例模式
<sectionid"nice"datatool"mdnice编辑器"datawebsite"https://www.mdnice.com"style"fontsize:16px;color:black;lineheight:1.6;wordspacing:0px;letterspacing:0px;word
Stella981 Stella981
3年前
JavaScript面向对象编程的15种设计模式
在程序设计中有很多实用的设计模式,而其中大部分语言的实现都是基于“类”。在JavaScript中并没有类这种概念,面向对象编程不是基于类,而是基于原型去面向对象编程,JS中的函数属于一等对象,而基于JS中闭包与弱类型等特性,在实现一些设计模式的方式上与众不同。ps:本文之讲述面向对象编程的设计模式策略,JavaScript原型的基础请参考阮一峰面向
Wesley13 Wesley13
3年前
Java开发中的23种设计模式详解(转)
设计模式(DesignPatterns)                                 ——可复用面向对象软件的基础设计模式(Designpattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。毫无疑问,设计模式于己于他
Wesley13 Wesley13
3年前
unity工程师面试知识点之MVC架构+观察者模式
所谓设计模式通俗点理解就是解决固定问题的套路。而说起观察者模式又不得不提起客户端框架设计中最常用的实现逻辑:MVC架构观察者模式。MVC架构中的M、V、C分别是model、view、control的缩写。model:模型,处理数据逻辑部分view:界面,处理数据显示部分control:控制器,模型和界面的沟通桥梁,负责从视图读取数据,控制用
工程中实践的微服务设计模式
最近在读《微服务架构设计模式》,开始的时候我非常的好奇,因为在我印象中,设计模式是常说的那23种设计模式,而微服务的设计模式又是什么呢?这个问题也留给大家,在文末我会附上我对这个问题的理解。本次文章的内容主要是工作中对微服务设计模式的应用,希望能对大家有所
吾粲
吾粲
Lv1
明月却多情,随人处处行。
文章
4
粉丝
0
获赞
0