资讯专栏INFORMATION COLUMN

JavaScript设计模式之工厂模式

xiaotianyi / 1719人阅读

摘要:使用完全模式省略每个品牌的独有的属性方法这是一辆单车抽象工厂模式抽象工厂模式通过对类的工厂抽象使其业务用于对产品类簇的创建,而不负责创建某一类产品的实例。抽象类是一种声明但不能使用的类,当你使用时就会报错。

原文博客地址:https://finget.github.io/2018/10/12/factory/
工厂模式 简介
工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式使一个类的实例化延迟到了子类。而子类可以重写接口方法以便创建的时候指定自己的对象类型(抽象工厂)。
将 new 操作多带带封装,遇到new时,就要考虑是否该用工厂模式

模式作用:

对象的构建十分复杂

需要依赖具体的环境创建不同实例

处理大量具有相同属性的小对象

注意事项:

不能滥用工厂,有的时候仅仅是给代码增加复杂度

UML

在jquery中的应用
// product
class jQuery {
  constructor(selector) {
    let slice = Array.prototype.slice
    let dom = slice.call(document.querySelectorAll(selector))
    let len = dom ? dom.length : 0
    for (let i = 0; i < len; i++) {
        this[i] = dom[i]
    }
    this.length = len
    this.selector = selector || ""
  }
  append(node) {}
  addClass(name) {}
  html(data) {}
// 此处省略若干 API
}
// 工厂
window.$ = function (selector) {
  return new jQuery(selector)
}
简单工厂 与 抽象工厂 简单工厂模式
简单工厂模式:又叫静态工厂方法,由一个工厂对象决定创建某一种产品对象类的示例。主要用来创建同一类对象。

去KFC点一个汉堡,服务员给你的是个汉堡,而不是牛肉、面粉、佐料...

// KFC的类
class KFC {
  // 做汉堡
  makeHbg () {
    // ...繁琐的工序
    console.log("汉堡一个")
  }
  // 炸鸡腿
  makeChk () {
    // ...繁琐的工序
    console.log("鸡腿一个")
  }
}

// 某一家KFC的店铺
let kfcFactory = function (food) {
  let kfc = new KFC()
  switch (food) {
    case hamburger:
      return kfc.makeHbg()
      break;
    case chicken:
      return kfc.makeChk()
      break;
  }
}

// 对于顾客来说,他只需要‘传入’他需要的东西就好了,不用关心汉堡是怎么做出来的
kfcFactory(hamburger); // "汉堡一个"
工厂方法
工厂方法:通过对产品类的抽象使其创建业务主要负责用于创建多类产品的实例。

现在有个工厂来生成所有的共享单车,模拟一下工厂模式。

// 别较真 栗子不好吃 理解这种方式就行
let Ofo = function() {
  this.name = "ofo"
  // ... 省略每个品牌的独有的属性方法
  (function() {
    let div = document.createElement("div")
    div.innerHTML = "这是一辆ofo单车"
    document.getElementById("box").appendChild(div)
  })()
}

let Mobike = function() {
  this.name = "Mobike"
  // ... 省略每个品牌的独有的属性方法
  (function() {
    let div = document.createElement("div")
    div.innerHTML = "这是一辆Mobike单车"
    document.getElementById("box").appendChild(div)
  })()
}

let Hello = function() {
  this.name = "hello"
  // ... 省略每个品牌的独有的属性方法
  (function() {
    let div = document.createElement("div")
    div.innerHTML = "这是一辆hello单车"
    document.getElementById("box").appendChild(div)
  })()
}

let Blue = function() {
  this.name = "blue"
  // ... 省略每个品牌的独有的属性方法
  (function() {
    let div = document.createElement("div")
    div.innerHTML = "这是一辆blue单车"
    document.getElementById("box").appendChild(div)
  })()
}

let Bikefactory = function (type) {
  switch (type) {
    case "Ofo":
      return new Ofo()
      break;
    case "Mobike":
      return new Mobike()
      break;
    case "Hello":
      return new Hello()
      break;
    case "Blue":
      return new Blue()
      break;
  }
}
安全模式类
安全模式类是为了解决错误使用类而造成的错误。
var Demo = function() {}
Demo.prototype={
  show: function() {
    console.log("Hello Demo")
  }
}
// 正确使用
var d = new Demo()
d.show();
// 错误使用
var d = Demo()
d.show(); // Uncaught TypeError:Cannot read property "show" of undefined

为了避免这类错误的发生,在构造函数开始时先判断当前对象this指代的是不是类(Demo)。

var Demo = function () {
  if (!(this instanceof Demo)) {
    return new Demo()
  }
}
var d =Demo();
d.show(); // "Hello Demo"

上面这样写,我们发现当共享单车的种类越来越多,需要添加新的共享单车时,就需要修改两处的代码,所以可以对它进行修改,按工厂模式方法来做。

let Bikefactory = function (name) {
    // 使用完全模式
  if (this instanceof Bikefactory) {
    let s = new this[type](name)
    return s;
  } else {
    return new Bikefactory(name)
  }
}
Bikefactory.prototype = {
  Ofo: function() {
      this.name = "ofo"
      // ... 省略每个品牌的独有的属性方法
      (function() {
        let div = document.createElement("div")
        div.innerHTML = "这是一辆ofo单车"
        document.getElementById("box").appendChild(div)
      })()
  },
  Mobike: function() {
    ....
  },
  ...
}
抽象工厂模式
抽象工厂模式:通过对类的工厂抽象使其业务用于对产品类簇的创建,而不负责创建某一类产品的实例。
抽象类

在JavaScript中abstract是一个保留字,所以目前来说还不能像传统的面向对象语言那样轻松的创建抽象类。抽象类是一种声明但不能使用的类,当你使用时就会报错。

// 抽象类
let Car = function() {}
Car.prototype = {
  run: function() {
    return new Error("抽象方法不能调用!")
  }
}
// 在ES6中定义抽象类
class Car {
  constructor() {
    if (new.target === Car) {
      throw new Error ("抽象类不能实例化!")
    }
  }
}

定义的Car中有一个run方法,继承与Car的子类都会拥有直接使用,需要重写。这也是抽象类的一个作用,即定义一个产品簇,并声明一些必备的方法,如果子类中没有重写这些方法,直接使用就会抛出错误。

抽象工厂
var XMLHttpFactory = function() {}

XMLHttpFactory.prototype = {
// 如果真的要调用这个方法会抛出一个错误,它不能被实例化,只能用来派生子类
  createFactory: function () {
    throw new Error("This is an abstract class")
  }
}

// 经典继承
var XHRHandler = function () {
    XMLHttpFactory.call(this) 
}
XHRHandler.prototype = new XMLHttpFactory()
XHRHandler.prototype.constructor = XHRHandler

XHRHandler.prototype.createFactory = function() {
  var XMLHttp = null;
  if(window.XMLHttpRequest) {
    XMLHttp = new XMLHttpRequest()
  } else if (window.ActiveXObject){
    XMLHttp = new ActiveXObject("Microsoft.XMLHttp")
  }
  return XMLHttp;
}
如果没有看明白经典继承部分的代码,可以去看看原型,原型链,call/apply。

用ES6的语法来实现一下抽象工厂,还是用共享单车的例子来改写一下:

// 别较真 栗子不好吃 理解这种方式就行
class Bike {
  constructor(name) {
    if (new.target === Bike) {
      throw new Error("抽象类不能实例化!")
    }
    this.name = name;
    // ... 此处省略100行
  }
  // ... 此处省略100行
  init () {
    return new Error("抽象方法不能调用!")
  }
}
class Ofo extends Bike {
  constructor(name) {
    super("ofo")
    this.name = name;
    // ... 此处省略100行
  }
  // ... 此处省略100行
  init () {
    console.log("这是一辆ofo单车!")
  }
}

class Mobike extends Bike {
  ...
}
class Hello extends Bike {
  ...
}
class Blue extends Bike {
  ...
}
// ... 更多的单车
let Bikefactory = function (name) {
  switch (name) {
    case "Ofo":
      return new Ofo()
      break;
    case "Mobike":
      return new Mobike()
      break;
    case "Hello":
      return new Hello()
      break;
    case "Blue":
      return new Blue()
      break;
  }
}

抽象工厂只留了一个“口子”,它不做具体的事,由它的子类,根据自身情况重写方法。

最后

创建了一个前端学习交流群,感兴趣的朋友,一起来嗨呀!

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

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

相关文章

  • JavaScript基础学习——面向对象(对象创建工厂模式

    摘要:官方解释工厂是构造方法的抽象,抽象了创建具体对象的过程。工厂方法模式的实质是定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。 前言 上一章回顾了JS对象的属性类型,那么除了我们常用的new Object()构造函数创建对象和字面量方式创建对象的方式外,还需要用到更多的模式来解决对象被多次复用的问题。什么意思呢?就是我们很有可能会在各个地方去使用已经创建过的对象,但是对象...

    qpal 评论0 收藏0
  • 细谈JavaScript中的一些设计模式

    摘要:注意事项声明函数时候处理业务逻辑区分和单例的区别,配合单例实现初始化构造函数大写字母开头推荐注意的成本。简单工厂模式使用一个类通常为单体来生成实例。 @(书籍阅读)[JavaScript, 设计模式] 常见设计模式 一直对设计模式不太懂,花了一下午加一晚上的时间,好好的看了看各种设计模式,并总结了一下。 设计模式简介 设计模式概念解读 设计模式的发展与在JavaScript中的应用 ...

    30e8336b8229 评论0 收藏0
  • JavaScript设计模式一:工厂模式和构造器模式

    摘要:集中实例化的函数第一个实例第二个实例工厂模式的分类工厂模式分为简单工厂抽象工厂和智能工厂,工厂模式不显示地要求使用一个构造函数。工厂模式之弊大多数类最好使用关键字和构造函数,可以让代码更加简单易读。带原型的构造器中有一个名为的属性。 什么是模式 前阵子准备期末考试,挺累也挺忙的,实在闲不得空来更新文章,今天和大家说说javascript中的设计模式。 首先呢,我们需要知道的是:模式是一...

    MkkHou 评论0 收藏0
  • Javascript设计模式-工厂模式

    摘要:设计模式工厂模式最近阅读了几本设计模式方面的书籍学习之余整理下来方便以后的归纳和梳理设计模式工厂模式创造工厂模式是一种创建性模式也就是一种创建对象的最佳实践首先我们需要理解为什么我们需要工厂模式想象一个场景如果你要求去买一些东西板烧鸡腿 Javascript设计模式-工厂模式 最近阅读了几本设计模式方面的书籍,学习之余整理下来,方便以后的归纳和梳理 设计模式-工厂模式 创造工厂模式是一...

    feng409 评论0 收藏0
  • JavaScript设计模式

    摘要:依赖于接口的设计模式下面列出的设计模式,尤其依赖接口工厂模式。这些私用的静态成员可以从构造器内部访问,这意味着所有私用函数和特权函数都能访问它们。构造器静态特权方法封装之弊私用方法很难进行单元测试。 1.弱类型语言 在JavaScript中,定义变量时不必声明其类型。但这并不意味着变量没有类型。一个变量可以属于几种类型之一,这取决于其包含的数据。JavaScript中有三种原始类型:...

    mingzhong 评论0 收藏0

发表评论

0条评论

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