资讯专栏INFORMATION COLUMN

观察者模式的一种运用

nevermind / 1720人阅读

摘要:采用观察者模式,通过其订阅发布机制,可以简化数据传输的过程,使每个模块独立起来,我们的模块能更加专注于业务代码的编写。

场景

如上图,在一个歌曲详情模块,假设有2个子模块,歌曲模块和评论模块。

在歌曲模块和评论模块中都有评论数量这个属性,当用户在评论模块发布了一条评论后,评论模块和歌曲模块的数量要同步更新。

评论模块的数量很好更新,歌曲模块的评论数量怎么同步更新呢?

下面介绍几种实现方法。
1. 双向绑定实现

思路:

在AppComponent将评论数量count作为输入参数(@Input)传递给CommentComponent和MusicComponent,当AppComponent中的评论数量改变时,MucisComponent中的评论数量也会同时改变。
当CommentComponent更新评论数量count时,通过输出参数(@Output)更新AppComponent中的评论数量count,MusicComponent中的评论数量count就会跟着改变了。

AppComponent

import { Component } from "@angular/core";

@Component({
  selector: "app-root",
  template: `
` }) export class AppComponent { count:number = 0; constructor() { } }

MusicComponent

import { Component, Input } from "@angular/core";

@Component({
  selector: "app-music",
  template: `

歌曲模块

评论数:{{ count }}
`, styleUrls: ["./music.component.css"] }) export class MusicComponent{ // 评论数 @Input() count:number; constructor() { } }

CommentComponent

import { Component, EventEmitter, Input, Output } from "@angular/core";

@Component({
  selector: "app-comment",
  template: `

评论

评论数:{{ count }}
  • {{ item }}
` }) export class CommentComponent { // 评论数 @Input() count:number = 0; // 评论数改变事件 @Output() countChange:EventEmitter = new EventEmitter(); // 评论列表 comments:string [] = []; constructor() { } // 发送评论 send(content) { if (content.value) { this.comments.push(content.value); this.count++; this.countChange.emit(this.count); } } }

2. 观察者模式实现

思路

构建一个观察者对象,观察者对象拥有注册(regist),发布(fire),移除(remove)三个方法。在angular2中可以通过依赖注入注入到CommentComponent和MusicComponent。

在MusicComponent中注册(regist),‘count’ 事件。

当用户发送评论时,在CommentComponent中发布(fire),‘count’事件。

构造观察者对象

import { Injectable } from "@angular/core";

@Injectable()
export class ObserverService {
    /**
     * 消息队列
     * 用数组保存每一种消息的事件队列,
     * eventList["count"] = []
     * 注册消息时将事件回调函数push到事件队列
     * eventList["count"].push(fn)
     * 发布消息时依次执行消息队列中的每一个回调函数
     * for(let fn of eventList["count"]) {
     *    fn(data);
     * }
     */ 
    eventList = {};

    constructor() {

    }

    /**
     * 发布消息
     * @param name 消息名
     * @param data 消息数据
     */
    fire(name:string, data:any) {
        if (this.eventList[name]) {
            const fns = this.eventList[name];
            for(let fn of fns) {
                fn(data);
            }
        }
    }

    /**
     * 注册消息
     * @param name 
     * @param fn 
     */
    regist(name:string, fn:any) {
        if (typeof fn === "function") {
            const fns = this.eventList[name];
            if (fns) {
                fns.push(fn);
            } else {
                this.eventList[name] = [fn];
            }
        }
    }

    /**
     * 移除消息
     * @param name 
     * @param fn 
     */
    remove(name:string, fn:any) {
        const fns = this.eventList[name];
        if (fns) {
            if ( fn ) {
                let i;
                for(i = 0; i < fns.length; i++) {
                    if (fns[i] === fn) {
                        break;
                    }
                }
                if (i < fns.length) {
                    fns.splice(i, 1);
                }
            } else {
                fns.length = 0;
            }
        }
    }
}

AppComponent

import { Component } from "@angular/core";

@Component({
  selector: "app-root",
  template: `
` }) export class AppComponent { constructor() { } }

MusicComponent

import { ObserverService } from "../service/observer.service";
import { Component, Input } from "@angular/core";

@Component({
  selector: "app-music",
  template: `

歌曲模块

评论数:{{ count }}
`, styleUrls: ["./music.component.css"] }) export class MusicComponent{ // 评论数 count:number; constructor(private observiceService:ObserverService) { // 注册消息 this.observiceService.regist("count", count => this.count = count); } }

CommentComponent

import { ObserverService } from "../service/observer.service.2";
import { Component, EventEmitter, Input, Output } from "@angular/core";

@Component({
  selector: "app-comment",
  template: `

评论

评论数:{{ count }}
  • {{ item }}
` }) export class CommentComponent { // 评论数 count:number = 0; // 评论列表 comments:string [] = []; constructor(private observiceService:ObserverService) { } send(content) { if (content.value) { this.comments.push(content.value); this.count++; // 发布消息 this.observiceService.fire("count", this.count); } } }

3. 使用Rxjs中的Subject实现

subject参考

SubjectService

import { Observable, Subject } from "rxjs/Rx";
import { Injectable } from "@angular/core";

@Injectable()
export class SubjectService {

count:number = 0;
comment:Subject;

constructor() {
    this.comment = new Subject();
}

}

AppComponent

import { Component } from "@angular/core";

@Component({
  selector: "app-root",
  template: `
` }) export class AppComponent { constructor() { } }

MusicComponent

import { SubjectService } from "../service/subject.service";
import { Component, Input } from "@angular/core";

@Component({
  selector: "app-music",
  template: `

歌曲模块

评论数:{{ count }}
`, styleUrls: ["./music.component.css"] }) export class MusicComponent{ // 评论数 count:number; constructor(private subjectService:SubjectService) { // 注册消息 this.subjectService.comment.subscribe(count => this.count = count); } }

4. 小结

在使用双向绑定进行多个的模块间的数据传输时,可以看到,当需要传递某个变量时,我们需要在每个模块中构造对应的@Input和@Output,借助父模块来进行传递数据,过程比较繁琐。
AppComponent

CommentComponent

MusicComponent

采用观察者模式,通过其订阅发布机制,可以简化数据传输的过程,使每个模块独立起来,我们的模块能更加专注于业务代码的编写。
AppComponent

MusicComponent

CommentComponent

借助Rxjs的Subject,我们能很方便的实现同样的功能。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88700.html

相关文章

  • Java设计模式概述

    摘要:设计模式的类别设计模式一共分为种类型,共种。属于结构型的设计模式适配器模式桥接模式装饰模式组合模式外观模式享元模式代理模式。问题描述了应该在何时使用设计模式。解决方案描述了设计的组成成分,它们之间的相互关系及各自的职责和协作方式。 设计模式概述 1. 设计模式是什么 我们在平时编写代码的过程中,会遇到各种各样的问题,细想一下很多问题的解决思路大致一样的,这时候你就可以把解决问题的思路整...

    leon 评论0 收藏0
  • 互联网常用设计模式——通往架构师的第一步

    摘要:设计模式的分类经典应用框架中常见的设计模式分为三类创建型模式对类的实例化过程的抽象。对象的结构模式是动态的。对象的行为模式则使用对象的聚合来分配行为。设计模式是个好东西,以后肯定还要进一步的学习,并且在项目中多实践,提升自己的设计能力。 什么是设计模式? Christopher Alexander 说过:每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样...

    张红新 评论0 收藏0
  • php设计模式

    摘要:我们今天也来做一个万能遥控器设计模式适配器模式将一个类的接口转换成客户希望的另外一个接口。今天要介绍的仍然是创建型设计模式的一种建造者模式。设计模式的理论知识固然重要,但 计算机程序的思维逻辑 (54) - 剖析 Collections - 设计模式 上节我们提到,类 Collections 中大概有两类功能,第一类是对容器接口对象进行操作,第二类是返回一个容器接口对象,上节我们介绍了...

    Dionysus_go 评论0 收藏0
  • php设计模式

    摘要:我们今天也来做一个万能遥控器设计模式适配器模式将一个类的接口转换成客户希望的另外一个接口。今天要介绍的仍然是创建型设计模式的一种建造者模式。设计模式的理论知识固然重要,但 计算机程序的思维逻辑 (54) - 剖析 Collections - 设计模式 上节我们提到,类 Collections 中大概有两类功能,第一类是对容器接口对象进行操作,第二类是返回一个容器接口对象,上节我们介绍了...

    vspiders 评论0 收藏0
  • 云计算,让服务触手可及(大数据观察·云)

    摘要:当云计算成为一种公共服务,社会创新的成本也由此大幅降低。在全球市场,中国云计算公司仍处于追赶状态,今后有望借助服务一带一路的机遇加速发展。数据来源:《省级政府网上政务服务能力调查评估报告(2018)》、阿里巴巴、腾讯制图:郭 祥习近平总书记在致首届数字中国建设峰会的贺信中指出,当今世界,信息技术创新日新月异,数字化、网络化、智能化深入发展,在推动经济社会发展、促进国家治理体系和治理能力现代化...

    jerry 评论0 收藏0

发表评论

0条评论

nevermind

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<