JS 设计模式之:工厂模式定义与实现方法浅析


Posted in Javascript onMay 06, 2020

本文实例讲述了JS 设计模式之:工厂模式定义与实现方法。分享给大家供大家参考,具体如下:

前言

上次我们介绍了单例模式,没看过的小伙伴可以看这个链接:

浅析 JS 设计模式之:单例模式

今天来说一说一种常见的设计模式:工厂模式。

工厂模式是一种创建对象的 创建型模式,遵循 DRY(Don't Repeat Yourself)原则。在该模式下,代码将会根据具体的输入或其他既定规则,自行决定创建哪种类型的对象。简单点儿说就是,动态返回需要的实例对象

回顾上次的例子

让我们继续使用单例模式中的例子,一个日志工具 Logger :

class Logger {
 log (...args) {
  console.log(...args);
 }
}

上面是最核心的 api,每次使用都需要使用 new Logger() 来创建一个 logger 对象,然后使用方法就和 console 一样啦~

多种 Logger

假如我们现在的代码要支持 electron 环境,即日志既可以是 console 日志,也可以是 file 日志,那么我们就需要有两种类型的 logger:

ConsoleLogger

// logger/console.js
class ConsoleLogger {
 log (...args) {
  console.log(...args)
 }
}
export default ConsoleLogger

FileLogger

// logger/file.js
class FileLogger {
 log (...args) {
  dumpLog(...args)
 }
}
export default FileLogger

这里先不用管 dumpLog 的具体实现,只用知道它就是将日志写在文件中的即可~

使用工厂

我们已经有了两种类型的 logger,但是这两种 logger 的 api 实际上都是一样的,在项目中直接导入当然也可以使用,只不过每次都要导入对应类型的模块,然后再使用,像下面这样:

使用 console logger

import ConsoleLogger from './logger/console'
const logger = new ConsoleLogger()

使用 file logger

import FileLogger from './logger/file'
const logger = new FileLogger()

是不是很繁琐?如果还有其他 logger 类型,如远程日志,就会出现更多种使用方式了。为了把 logger 模块的使用方式统一,这时候就会用到工厂模式啦~

让我们新建一个 index.js

// logger/index.js
import ConsoleLogger from './console.js'
import FileLogger from './file.js'

function createLogger(type = 'console') {
 if (type === 'console') {
  return new ConsoleLogger()
 } else if (type === 'file') {
  return new FileLogger()
 }
 throw new Error(`Logger type not found: ${type}`)
}

export default createLogger

好了,这下我们的使用方式就会变成这样:

import createLogger from './logger'
// console logger
const logger1 = createLogger('console')
// file logger
const logger2 = createLogger('file')

重构一下

上面的 if else 不是很优雅?如果有更多中 logger 类型添加起来很麻烦?那我们可以使用对象来映射一下,从而抛弃 if else,同时添加一个 logger 选项。

// logger/index.js
import ConsoleLogger from './console.js'
import FileLogger from './file.js'

const loggerMap = {
 console: ConsoleLogger,
 file: FileLogger
}
// 可选参数一般放在最后面
function createLogger(options, type = 'console') {
 const Logger = loggerMap[type]
 if (Logger) {
  return new Logger(options)
 }
 throw new Error(`Logger type not found: ${type}`)
}
上面这种封装的方式,其实也符合 SOLID 原则中的 开闭原则,即 对扩展开放,对修改关闭,每当我们添加一种 logger 类型时,只需要新增一个文件,然后将构造器注册进 loggerMap 中即可。而外面的使用方式都是不变的,这样就用最少的修改完成了功能的新增,是不是很棒呀~

总结

下面我们来回顾一下工厂模式的优点:

  • 动态创建对象:可以用于需要在 运行时 确定对象类型的情况。
  • 抽象:封装了对象创建的细节,用户不会接触到对象的构造器,只需要告诉工厂需要哪种对象。
  • 可用性 / 可维护性:将相似的对象用一个工厂管理,提供统一的创建接口,满足 开闭原则,使我们可以轻松添加多种类型的对象,而无需修改大量代码。

好啦~!工厂模式就介绍到这里啦~ 下次我们讲一讲装饰器模式~

参考内容

  • JavaScript Object Oriented Patterns: Factory Pattern
  • 《JavaScript 设计模式》
  • 《JavaScript 面向对象编程指南》

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码运行效果。

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
js+FSO遍历文件夹下文件并显示
Mar 07 Javascript
jquery实现点击TreeView文本父节点展开/折叠子节点
Jan 10 Javascript
深入理解Javascript作用域与变量提升
Dec 09 Javascript
Area 区域实现post提交数据的js写法
Apr 22 Javascript
jquery操作复选框checkbox的方法汇总
Feb 05 Javascript
JavaScript数据类型之基本类型和引用类型的值
Apr 01 Javascript
jquery动感漂浮导航菜单代码分享
Apr 15 Javascript
vuejs开发组件分享之H5图片上传、压缩及拍照旋转的问题处理
Mar 06 Javascript
jQuery+ajax实现动态添加表格tr td功能示例
Apr 23 jQuery
jQuery 实现批量提交表格多行数据的方法
Aug 09 jQuery
vue debug 二种方法
Sep 16 Javascript
JS实现旋转木马轮播图
Jan 01 Javascript
JS 设计模式之:单例模式定义与实现方法浅析
May 06 #Javascript
基于vue3.0.1beta搭建仿京东的电商H5项目
May 06 #Javascript
JavaScript布尔运算符原理使用解析
May 06 #Javascript
ES5 模拟 ES6 的 Symbol 实现私有成员功能示例
May 06 #Javascript
Vue 的双向绑定原理与用法揭秘
May 06 #Javascript
微信小程序中使用 async/await的方法实例分析
May 06 #Javascript
JavaScript常用工具函数大全
May 06 #Javascript
You might like
php文件上传类完整实例
2016/05/14 PHP
PHP中通过getopt解析GNU C风格命令行选项
2019/11/18 PHP
JQuery扩展插件Validate 1 基本使用方法并打包下载
2011/09/05 Javascript
JavaScript高级程序设计阅读笔记(十六) javascript检测浏览器和操作系统-detect.js
2012/08/14 Javascript
鼠标选择动态改变网页背景颜色的JS代码
2013/12/10 Javascript
CSS3,HTML5和jQuery搜索框集锦
2014/12/02 Javascript
express的中间件basicAuth详解
2014/12/04 Javascript
jquery实现从数组移除指定的值
2015/06/24 Javascript
浅谈Javascript中substr和substring的区别
2015/09/30 Javascript
JavaScript来实现打开链接页面的简单实例
2016/06/02 Javascript
jquery判断类型是不是number类型的实例代码
2016/10/07 Javascript
Angular在模板驱动表单中自定义校验器的方法
2017/08/09 Javascript
ReactNative实现Toast的示例
2017/12/31 Javascript
clipboard.js在移动端复制失败的解决方法
2018/06/13 Javascript
「中高级前端面试」JavaScript手写代码无敌秘籍(推荐)
2019/04/08 Javascript
layui按条件隐藏表格列的实例
2019/09/19 Javascript
Django处理文件上传File Uploads的实例
2018/05/28 Python
python实现扫描ip地址的小程序
2019/04/16 Python
Python流程控制 if else实现解析
2019/09/02 Python
python基于socket实现的UDP及TCP通讯功能示例
2019/11/01 Python
python实现处理mysql结果输出方式
2020/04/09 Python
jupyter note 实现将数据保存为word
2020/04/14 Python
使用python matplotlib 画图导入到word中如何保证分辨率
2020/04/16 Python
HTML5超文本标记语言的实现方法
2020/09/24 HTML / CSS
巴西独家产品和现场演示购物网站:Shoptime
2019/07/11 全球购物
个人实习生的自我评价
2014/02/16 职场文书
晨会主持词
2014/03/17 职场文书
辩论赛主持词
2014/03/18 职场文书
初三学生个人自我评定
2014/04/06 职场文书
工伤事故赔偿协议书
2014/04/15 职场文书
投资意向协议书
2015/01/29 职场文书
幼儿园园长个人总结
2015/03/02 职场文书
2015年销售部工作总结范文
2015/04/27 职场文书
《法国号》教学反思
2016/02/22 职场文书
2019求职信:应届生求职信范文
2019/04/24 职场文书
python字典的元素访问实例详解
2021/07/21 Python