博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript常用设计模式
阅读量:6590 次
发布时间:2019-06-24

本文共 4707 字,大约阅读时间需要 15 分钟。

设计模式

设计模式是一种在长时间的经验与错误中总结出来可服用的解决方案。

设计模式主要分为3类:

创建型设计模式:专注于处理对象的创建

Constructor构造器模式,Factory工厂模式,Singleton单例模式,builder生成器模式

结构型设计模式:对象间组合,建立对象之间的关系

Decorator装饰者模式,Facade外观模式,Flyweight享元模式,Adapter适配器模式,Proxy代理模式

行为设计模式:简化和改善对象间的通信

Mediator中介者模式,Observer观察者模式

常用的设计模式

1. 观察者模式

一个目标对象维持着一系列依赖于它的对象,将有关状态的任何变更自动通知观察者们。在观察者模式中,观察者需要直接订阅目标对象,观察者与目标对象之间有一定的依赖关系。 有4个重要的概念

  • 目标对象(被观察者):维护一组观察患者,提供管理观察者的方法。
  • 观察者: 提供一个更新接口,用于收到通知时,进行更新
  • 具体目标对象:代表具体的目标对象
  • 具体观察者:代表具体的观察者
// 目标对象class Subject {  constructor() {    // 观察者列表    this.observers = []  }  addObserver(observer) {    this.observers.push(observer)  }  removeObserver() {    this.observers.pop()  }  notify() {    this.observers.forEach(observer => {      observer.update()    })  }}// 观察者class Observer {  constructor() {    // 使用时会被具体update方法覆盖    this.update = function () {        // ..    }  }}// 具体目标对象class currentSubject extends Subject {  constructor() {    super()      }  // 其他自定义方法  dosomething() {    console.log('currentSubject change')    this.notify()  }}// 具体观察者class currentObserver extends Observer {    constructor() {        super()    }    // 重写update    update() {        console.log('change!')    }}// 订阅let curSubject = new currentSubject()let curObserver = new currentObserver()curSubject.addObserver(curObserver)// 触发curSubject.dosomething()// currentSubject change

2.发布/订阅模式

发布订阅模式可以说是观察这模式的一种变体,一种实现。它使用一个主题/事件通道,介于发布者和订阅者之间,避免了发布者和订阅者之间的依赖关系。

class PubSub {  constructor() {// 主题/事件通道    this.topics = {}  }  publish(topic, args) {    if (!this.topics[topic]) {      return    }    let subscribers = this.topics[topic]    subscribers.forEach(subscriber => {        subscriber.updata(args)    })  }  subscribe(topic, subscriber ) {    if (!this.topics[topic]) {      this.topics[topic] = []    }    this.topics[topic].push(subscriber )  }}let pubsub = new PubSub()pubsub.subscribe('one', subscriber )pubsub.publish('one', 'some args')

3. 工厂模式

工厂函数提供一个通用的接口来创建对象,我们可以指定我们希望创建的对象类型,我们通知工厂函数需要什么类型的对象并提供对应的数据,返回对应的实例。

class Car {  constructor(options) {    this.doors = options.doors || 4;    this.state = options.state || "brand new";    this.color = options.color || "silver";  }}class Truck {  constructor(options) {    this.state = options.state || "used";    this.wheelSize = options.wheelSize || "large";    this.color = options.color || "blue";  }}function vehicleFactory (options) {  if (options.type === 'car') {    return new Car(options)    } else {    return new Truck(options)  }}

何时使用工厂模式

  • 当我们的对象比较复杂的时候。
  • 当我们需要根据不同情况创建不同对象实例的时候。
  • 当我们需要创建许多相似对象的时候。

缺点

  • 使用不当会增加程序的复杂度

4. 抽象工厂模式

抽象工厂模式,将对象的实现细节抽离出来。适用于需要和多种对象一起工作的场景。

class Truck {  constructor(options) {    this.state = options.state || "used";    this.wheelSize = options.wheelSize || "large";    this.color = options.color || "blue";  }}class Car {  constructor(options) {    this.doors = options.doors || 4;    this.state = options.state || "brand new";    this.color = options.color || "silver";  }}class AbstractFactory {  constructor() {    this.types = {}  }  registerFactory(type, factory) {    this.types[type] = factory  }  getInstance(type, args) {    let factory = this.types[type]    if (factory) {      return new factory(args)    }  }}let abstractFactory = new AbortController()abstractFactory.registerFactory('car', Car)abstractFactory.registerFactory('truck', Truck)abstractFactory.getInstance('car', options)abstractFactory.getInstance('truck', options)

5. 单例模式

单例模式限制一个类只有一个实例化对象。

class Obj(data) {  // ....}// 利用闭包实现单例模式,确保obj类只有一个实例function singleton (data) {  var instance;  return function () {    if (!instance) {      instance = new Obj(data)    }    return instance  }}

6. 中介者模式

中介者模式就是提供一个中心点给系统不同组件之间进行通信,降低系统组件之间的耦合程度。

// 实现与发布/订阅模式类似

观察者模式和发布订阅模式专注于维护目标对象和观察者之间的关系,当主题对象发送变化时,通知所有对改主题感兴趣的观察者。而中介者模式的话,专注于限制对象的通信必须通过中介者来通信。两者都提倡松耦合。

7. 装饰者模式

装饰者模式,通过一个装饰类对现有动态添加行为,以及对原有行为进行装饰。

// o为已有对象    var M20 = function(o){    // 这里定义一个装饰类        var str = '20多岁的时候,';        // o是传入的对象,调用传入对象的方法,加以装饰        this.eat = function(){            return str + o.eat()+",肥得很!";        };        this.drink = function(){            return str + o.drink()+",就是个水桶!";        };        this.coding = function(){            return str + o.coding()+",代码又写得撇!";        };    }    alert(new M20(david).eat());    // 20多岁的时候,大卫是个大胖子,一天只晓得吃,肥得很!    alert(new M20(david).drink());    // 20多岁的时候,大卫除了吃就是喝,就是个水桶!    alert(new M20(david).coding());    // 20多岁的时候,写代码吧,大卫,代码又写得撇!

8. 适配器模式

使用一个新的接口对现有的接口进行包装,处理数据与接口的不匹配。

function api (x1, x2, x3) {  console.log(x1 + x2 + x3);  // 用console.log来模拟接口的相关操作}var data = {  a: '我',  b: '很',  c: '帅'}function adapterApi (o) {  // 通过适配器函数来调用目的api  api(o.a, o.b, o.c);} adapterApi(data);// 我很帅

原文发布时间为:2018年07月02日
原文作者:掘金
本文来源: 如需转载请联系原作者

你可能感兴趣的文章
烂泥:NFS存储与VSphere配合使用
查看>>
oracle数据库字符集US7ASCII,在java中处理中文问题
查看>>
运维自动化之使用PHP+MYSQL+SHELL打造私有监控系统(四)
查看>>
自制Extjs API - JS Duck3
查看>>
闲话iBatis
查看>>
解析linux下磁盘乱序的问题
查看>>
Thinkphp框架支持MySQL的读写分离
查看>>
【Cocoa(mac) Application 开发系列之三】自定义NSView并绘制一些常见的图形及字符串...
查看>>
BDB c++例子,从源码编译到运行
查看>>
Unity中关于作用力方式ForceMode的功能注解
查看>>
Latch1:PageIOLatch和PageLatch
查看>>
.NET I/O 学习笔记:对文件和目录进行解压缩操作
查看>>
Geoserver初步使用
查看>>
VS2008环境使用MFC操作读取excel文件
查看>>
AS3.0 正则表达式规则
查看>>
Windows Mobile下如果进行Native C++多线程的开发
查看>>
并发控制-简单总结
查看>>
查看JVM统计信息
查看>>
备份服务器端SQL SERVER数据库至本地目录
查看>>
【温故而知新-Javascript】使用Web存储
查看>>