几种常见的设计模式

268 阅读4分钟

简单工厂模式

工厂模式其实就是将创建对象的过程封装起来。就像工厂一样,我们不需要关心工厂怎么制造东西,我们只需要提供材料,就能得到我们想要的东西。

先写一个简单构造函数。

function Clothes(color, size, gender) {
    this.color = color
    this.size = size
    this.gender = gender 
}
const clotheA = new Clothes(color, size, gender)

很好,我们可以通过Clothes制造出很多件的衣服,但是现在的衣服只有颜色,尺寸,性别三种,并不能区分是上衣还是裤子,没有种类这个属性。如果需要加上的话:

function Jacket(color, size, gender) {
    this.color = color
    this.size = size
    this.gender = gender 
    this.kind = '上衣'
}
function Sweater (color, size, gender) {
    this.color = color
    this.size = size
    this.gender = gender 
    this.kind = '毛衣'
}
function Jeans (color, size, gender) {
    this.color = color
    this.size = size
    this.gender = gender 
    this.kind = '牛仔裤'
}

很明显,如果衣服种类多的话,需要创建很多个构造函数。所以,我们可以做一个工厂来帮我们解决这种繁琐的操作。

function Clothes(color, size, gender,kind) {
    this.color = color
    this.size = size
    this.gender = gender 
    this.kind = kind 
}
function clotheFactory(color, size, gender,kind) {
    switch(kind) {
        case 'Jacket':
            kind = '上衣'
            break
        case 'Sweater':
            kind = '毛衣'
            break
        case 'Jeans':
            kind = '牛仔裤'
            break
        }
        return new Clothes(color, size, gender, kind)
}
let Jacket = clotheFactory('红色','43码','男装','Jacket'); 
console.log(Jacket) //Clothes {color: "红色", size: "43码", gender: "男装", kind: "上衣"}

单例模式

什么是单例模式?单例模式就是保证一个类仅有一个实例,并提供一个访问它的全局访问点。

function Clothes(color, size, gender) {
    this.color = color
    this.size = size
    this.gender = gender 
}
const ClothesA = new Clothes('红色','43码','男装')
const ClothesB = new Clothes('红色','43码','男装')
console.log(ClothesA ===ClothesB);//false

很明显ClothesA和ClothesB是相互独立的对象,各占一块内存空间,这并不是我们想要的。

如何实现一个单例模式,简单的做法就是使用一个变量来标志当前是否已经为某个类创建过实例,如果是,则在下一次获取该类的实例时,直接返回之前创建的实例。

function Clothes(color, size, gender) {
    this.color = color
    this.size = size
    this.gender = gender
    this.instance = null //用来标记是否已经创建过实例
}
Clothes.prototype.getColor = function(){ 
 console.log ( this.color ); 
};
//用来检查是否已经创建过实例
Clothes.getInstance = function( color ){ 
 if ( !this.instance ){ 
 this.instance = new Clothes( color ); 
 } 
 return this.instance; 
};
var ClothesA =  Clothes.getInstance('红色')
var ClothesB =  Clothes.getInstance('黄色')
console.log(ClothesA === ClothesB);//true

当然,也可以使用闭包的形式实现。

Clothes.getInstance = (function( color ){ 
    let instance = null
    return function(){
        if (!instance ){ 
        instance = new Clothes( color ); 
        } 
    }
 return instance; 
})()

策略模式

策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。

但是直接看定义比较难理解,所以可以用一些简单的例子来讲解。

比如说有这样的一个场景:有一天,公司的这季度的业绩不错,老板打算给个员工发放绩效奖金。

如果该员工业绩为优,工资在原有的基本工资上+20%绩效。员工业绩为良,工资在原有的基本工资上+10%绩效。员工业绩为及格,工资在原有的基本工资上+5%绩效。

如果是一名初级开发者,看到这个场景,可能会这样写:

function getSalary(grade,basicSalary){
    if(grade==='优'){
        return basicSalary * 1.2
    }
    if(grade==='良'){
        return basicSalary * 1.1
    } 
    if(grade==='及格'){
        return basicSalary * 1.05
    }
}

功能上看这没什么问题,但是一个函数里面处理了多个逻辑,很明显违背了“单一功能”的原则。

因此我们可以做一下调整。

function gradeYou(basicSalary){
    return basicSalary * 1.2
}
function gradeliang(basicSalary){
    return basicSalary * 1.1
}
function gradeJige(basicSalary){
    return basicSalary * 1.05
}
function getSalary(grade,basicSalary){
    if(grade==='excellent'){
        return gradeYou(basicSalary)
    }
    if(grade==='good'){
        return gradeliang(basicSalary)
    } 
    if(grade==='pass'){
        return gradeJige(basicSalary)
    }
}

很好,现在各个函数都只负责一件事,但是getSalary()里面,还是很多的if,如果老板说,业绩不及格的人没有绩效奖金可以拿,那么就只能再添加一个if。

function getSalary(grade,basicSalary){
    if(grade==='excellent'){
        return gradeYou(basicSalary)
    }
    if(grade==='good'){
        return gradeliang(basicSalary)
    } 
    if(grade==='pass'){
        return gradeJige(basicSalary)
    }
     if(grade==='fail'){
        return gradeBujige(basicSalary)
    }
}

这样很明显不符合将不变的部分和变化的部分隔开这种"开放封闭"的原则。为了实现对扩展开放,对修改封闭。我们可以使用对象映射的形式改造。

var salaryRule = {
    excellent(basicSalary) {
        return basicSalary * 1.2
    },
    good(basicSalary) {
        return basicSalary * 1.1
    }, 
    pass(basicSalary) {
        return basicSalary * 1.05
    },
}
function getSalary(grade, basicSalary) {
  return salaryRule[grade](basicSalary)
}

如果以后想要在添加一个不及格,只要给salaryRule新增一个映射关系就好了

salaryRule.fail = function (basicSalary){
return basicSalary
}

参考文献

《JavaScript设计模式与开发实践》

《JavaScript 设计模式核心原理与应用实践》