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 相关文章推荐
Jquery实现侧边栏跟随滚动条固定(兼容IE6)
Apr 02 Javascript
JavaScript学习笔记之基础语法
Jan 22 Javascript
jquery中toggle函数交替使用问题
Jun 22 Javascript
Bootstrap模态对话框的简单使用
Apr 29 Javascript
javaScript中的原型解析【推荐】
May 05 Javascript
bootstrap table复杂操作代码
Nov 01 Javascript
理解javascript async的用法
Aug 22 Javascript
微信小程序录音与播放录音功能
Dec 25 Javascript
Vue SPA单页应用首屏优化实践
Jun 28 Javascript
Vue 组件封装 并使用 NPM 发布的教程
Sep 30 Javascript
Angular Material Icon使用详解
Nov 07 Javascript
JS面向对象编程实现的拖拽功能案例详解
Mar 03 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版(4)
2006/10/09 PHP
PHP下escape解码函数的实现方法
2010/08/08 PHP
使用PHP强制下载PDF文件示例
2014/01/17 PHP
在Laravel5.6中使用Swoole的协程数据库查询
2018/06/15 PHP
动态改变textbox的宽高的js
2006/10/26 Javascript
解决jquery .ajax 在IE下卡死问题的解决方法
2009/10/26 Javascript
javascript制作的网页侧边弹出框思路及实现代码
2014/05/21 Javascript
jQuery ajax serialize() 方法使用示例
2014/11/02 Javascript
多个jQuery版本共存的处理方案
2015/03/17 Javascript
详解AngularJS中的依赖注入机制
2015/06/17 Javascript
JavaScript的Backbone.js框架入门学习指引
2016/05/07 Javascript
Markdown+Bootstrap图片自适应属性详解
2016/05/21 Javascript
使用jQuery卸载全部事件的思路详解
2017/04/03 jQuery
详解Vue用自定义指令完成一个下拉菜单(select组件)
2017/10/31 Javascript
vue2.0 如何把子组件的数据传给父组件(推荐)
2018/01/15 Javascript
js中async函数结合promise的小案例浅析
2019/04/14 Javascript
vue使用localStorage保存登录信息 适用于移动端、PC端
2019/05/27 Javascript
vue实现日历备忘录功能
2020/09/24 Javascript
微信小程序用canvas画图并分享
2020/03/09 Javascript
[38:23]2014 DOTA2国际邀请赛中国区预选赛 5 23 CIS VS LGD第一场
2014/05/24 DOTA
[49:08]Secret vs VP 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/20 DOTA
Python实现读写sqlite3数据库并将统计数据写入Excel的方法示例
2017/08/07 Python
Django+JS 实现点击头像即可更改头像的方法示例
2018/12/26 Python
解决python打不开文件(文件不存在)的问题
2019/02/18 Python
使用matplotlib中scatter方法画散点图
2019/03/19 Python
使用python turtle画高达
2020/01/19 Python
python实现最短路径的实例方法
2020/07/19 Python
关于PyCharm安装后修改路径名称使其可重新打开的问题
2020/10/20 Python
html5 兼容IE6结构的实现代码
2012/05/14 HTML / CSS
美国本地交易和折扣网站:LocalFlavor.com
2017/10/26 全球购物
澳洲在线厨具商店:Kitchen Style
2018/05/05 全球购物
项目专员岗位职责
2013/12/04 职场文书
水利专业大学生职业生涯规划书范文
2014/09/17 职场文书
2016年安康杯竞赛活动总结
2016/04/05 职场文书
年终工作总结范文
2019/06/20 职场文书
漫画《尖帽子的魔法工坊》宣布动画化
2022/04/06 日漫