前端简单的工厂模式

89 阅读4分钟

设计模式需要注意的几大原则

设计原则是设计模式的指导理论,它通常包括:单一功能开放封闭里式替换接口隔离依赖反转五大原则,但是实际中我们常常需要注意的,仅仅是里面的单一功能开放封闭

通常我们都希望写的代码不用去迭代更新,这样可以“不考虑”代码的健壮性和维护性,只要能够实现功能,就可以了,但是在实际开发过程中,无论是什么样的需求,都会迭代更新,所以就需要让代码易读,易于维护,拒绝“流水账式写法”。这个迭代更新的过程就是变化,我们就需要通过封装变化的方式来使代码变得简洁,而这也是设计模式的核心思想,以确保变化部分足够灵活,不变的部分足够稳定

《设计模式:可复用面向对象软件的基础》这本书中,阐述了设计模式领域的开创性成果将23种设计模式按照“创建型”、“行为型”和“结构型”进行划分:

  • 创建型:1.单例模式、2.原型模式、3.构造器模式、4.工厂模式、5.抽象工厂模式
  • 结构型:1.桥接模式、2.外观模式、3.组合模式、4.装饰器模式、5.适配器模式、6.代理模式、7.享元模式
  • 行为型:1.迭代器模式、2.解释器模式、3.观察者模式、4.中介者模式、5.访问者模式、6.状态模式、7.备忘录模式、8.策略模式、9.模版方法模式、10.职责链模式、11.命令模式

可以从模式名称看出,这23种设计模式都进行了封装变化:

  • 创建型模式封装了创建对象过程中的变化,它做的事情就是将创建对象的过程抽离
  • 结构型模式封装的是对象之间组合方式的变化,目的在于灵活地表达对象间的配合与依赖关系
  • 行为型模式将对象千变万化的行为进行抽离,确保我们能够更安全、更方便地对行为进行更改

例如如果我们录入少量用户信息时候,可能会直接定义参数式,但是数量多了就会显得代码量过于庞大,难以维护:

const user_1 = { name: '张三', age: 30, career: 'Python' }
const user_2 = { name: '李四', age: 31, career: 'JavaScript' }
const user_3 = { name: '王五', age: 32, career: 'Java' }
...

在上面的这个代码片段中,我们可以识别出,哪些是变化的“个性”,哪些是不变的“共性”,我们可以先使用构造函数的方式改造上面的代码片段

function User(name, age, career){
   this.name = name
   this.age = age
   this.career = career
}
const user_1 = new User('张三', 30, 'Python')
const user_2 = new User('李四', 31, 'JavaScript')
const user_3 = new User('王五', 32, 'Java')
...

其实上面的User就是一个构造器,在这个构造器中,将 name, age, career 三个共性的字段封装在了创建用户的过程中,同时开放赋值,取值。

简单的工厂模式

需求:现在在上面的代码中,将用户职责范围的工作进行描述,添加它的特殊标识。

部分开发者的第一反应可能会是创建多个构造器,如下:

function User_Python(name, age){
   this.name = name
   this.age = age
   this.career = 'Python'
   this.job = {
       start: '10:30',
       end: '19:30',
       work: ['Python code', 'Python bug fix']
   }
}
function User_JavaScript(name, age){
   this.name = name
   this.age = age
   this.career = 'JavaScript'
   this.job = {
       start: '10:30',
       end: '19:30',
       work: ['JavaScript code', 'JavaScript bug fix']
   }
}
function User_Java(name, age){
   this.name = name
   this.age = age
   this.career = 'Java'
   this.job = {
       start: '10:30',
       end: '19:30',
       work: ['Java code', 'Java bug fix']
   }
}
function Factory(name, age, career){
    switch(career) {
        case 'Python':
            return new User_Python(name, age)
            break
        case 'JavaScript':
            return new User_JavaScript(name, age)
            break
        case 'Java':
            return new User_Java(name, age)
            break
        ...
    }
}
const user_1 = new Factory('张三', 30, 'Python')
const user_2 = new Factory('李四', 31, 'JavaScript')
const user_3 = new Factory('王五', 32, 'Java')

我们通过上面的代码,可以看出,在构造器中,有大量冗余代码,如果要在每个用户信息添加公司名称,需要在多个构造器中都添加。我们可以将共性参数抽出来,对个性参数进行处理:

function User(name, age, career, job){
   this.name = name
   this.age = age
   this.career = career
   this.job = job
}
function Factory(name, age, career){
    let job = []
    switch(career) {
        case 'Python':
            job = ['Python code', 'Python bug fix']
            break
        case 'JavaScript':
            job = ['JavaScript code', 'JavaScript bug fix']
            break
        case 'Java':
            job = ['Java code', 'Java bug fix']
            break
        ...
    }
    return new User(name, age, career, job)
}
const user_1 = new Factory('张三', 30, 'Python')
const user_2 = new Factory('李四', 31, 'JavaScript')
const user_3 = new Factory('王五', 32, 'Java')

这样看来,不仅代码冗余降低了,可读性也变强了,由此看来,当创建对象时候,如果有多个共性与个性时候,可以优先考虑使用工厂模式,由此来降低开发成本。