从构造器模式到工厂模式

256 阅读4分钟

「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。

构造器模式

构造器模式可以用来处理创建多个相同属性的对象。

function Person(name,age){
    this.name = name
    this.age = age
}
let An = new Person('安',22)
let Qyt = new Person('权',22)

构造器模式可以用来处理创建多个相同属性的对象。

但是如果需要根据职业进行区分呢,还是可以用构造器解决。

但是就需要多个构造器了,比如前端开发,技术支持,产品经理等等

function FrontEnd(name,age){
    this.name = name
    this.age = age
    this.career = '前端开发'
}
function TechnicalSupport(name,age){
    this.name = name
    this.age = age
    this.career = '技术支持'
}

然后再创建一个函数,将变化的职业交给switch去处理,这样就算的上是简单工厂模式。

简单工厂模式

将对象的公用属性抽离到一个构造函数中,通过构造函数配合switch实现返回不同的对象。

function Factory(name,age,career){
    switch (career) {
        case 'FrontEnd':
            return FrontEnd(name,age)
            break
        case 'TechnicalSupport':
            return TechnicalSupport(name,age)
            break
        ...
    }
}
let An = Factory('安',22, 'FrontEnd')
let Qyt = Factory('权',22, 'TechnicalSupport')

但是这样会有一个问题,就是有很多工种的话就要单独写很多构造函数,找到两个构造函数的共性,抽离到一个构造函数中。

function worker(name,age,career,work){
    this.name = name
    this.age = age
    this.career = career
    this.work = work
}

function Factory(name,age,career){
    let work
    switch (career) {
        case 'FrontEnd':
            work = ['写代码','改bug']
            break
        case 'TechnicalSupport':
            work = ['沟通甲方','让程序员改bug']
            break
        default:
            work = null
    }
    return worker(name,age,career,work)
}

这样就可以无脑传参了,每次添加新职业只需要新增一条case就行了。

对于简单工厂的思考

以下对于简单工厂模式所想到的应用。

Redux中的action和reducer

action中通过构造函数创建不同的action

Image.png

在reducer中通过判断payload来决定返回不同的state

Image.png

抽象工厂

在实际业务中,复杂度可能并不是几个类或一个工厂可以解决,而是需要多个工厂

比如之前的例子,worker代表打工人,假如还有Boss呢?Boss有更多的权限,有比worker更多的属性。如果在工厂函数中针对Boss去修改,就违反了开放封闭原则-软件实体(类、模块、函数)可以扩展,但是不可修改。抽象工厂可以解决这样的问题。

什么是抽象工厂?

拿小米手机举例

// 手机工厂
class Phone {
    createPhone() {
        throw new Error("抽象工厂方法不允许直接调用,你需要将我重写!");
    }
}
// 小米手机工厂
class MiPhone extends Phone{
    createPhone() {
        return new xiaomi()
    }
}
// 抽象产品类-系统
class OS {
    showOS() {
        throw new Error("抽象工厂方法不允许直接调用,你需要将我重写!");
    }
}
// 系统的具体产品类
class xiaomi extends OS {
    showOS() {
        console.log('MIUI')
    }
}
let Mi12 = new MiPhone().createPhone()
Mi12.showOS() // MIUI

首先是手机工厂,也就是根据手机抽象出来的共性,根据共性去拓展(extends),就产生了小米手机工厂。

其次是系统工厂(手机必须得有系统才行),也就是根据手机系统抽象出来的共性,可以拓展出具体的MIUI系统。

如果这个工厂此时还需要给苹果生产手机该怎么做呢?就仅需要对于手机工厂拓展一个新类叫苹果手机工厂,而对于OS拓展一个新的类apple就可以了,这样就实现了拓展但不修改,不会违反开放封闭原则了。

class IPhone extends Phone{
    createPhone() {
        return new apple()
    }
}
class apple extends OS {
    showOS() {
        console.log('IOS')
    }
}
let IPhone13 = new IPhone().createPhone()
IPhone13.showOS() //IOS

抽象工厂总结

抽象工厂主要有四个关键角色。

  • 抽象工厂(抽象类):用于声明目标产品的共性,对应到上面的例子就是Phone类。
  • 具体工厂(用于生产具体的产品):继承于抽象工厂,实现了抽象工厂声明的方法,用于创建具体的产品。比如MiPhone, IPhone…
  • 抽象产品(抽象类下的产品的共性):具体工厂中的接口会依赖一些类,也就是一些更细节的东西。比如对于手机而言,就是系统、芯片等…
  • 具体产品(抽象产品的具体产品):拿操作系统来说,比如有MIUI、IOS等。

定义就是围绕着一个超级工厂创建其他工厂,在JS世界中应用并不广泛,但应当了解。()

总结

一个对象时使用构造模式(构造函数)、多个对象(有共性,不同点只有一个)时使用简单工厂(工厂函数)、多种对象(有共性,但多个属性都各不相同或需要拓展性)时使用抽象工厂。

参考链接:juejin.cn/book/684473…