【前端谈设计】单例模式

95 阅读6分钟

创建类型设计模式包含原型模式构造模式工厂模式抽象工厂模式建造模式单例模式,其中的工厂模式抽象工厂模式因为设计理念类似,所以在很多文章中都会把它们统称为工厂模式工厂模式又从服务目标的不同分为简单工厂模式工厂方法模式抽象工厂模式

在以前,因为工厂模式更适合服务于面向对象语言,所有了在JS语言中被提到的时间会很少,学不学也就无关紧要了,但是随着TS语言的发展,面向对象模式又在前端兴起,所有还不趁现在抓紧学习起来!!!!

简单工厂模式

例子:去银行取钱

场景:在银行开设之初,取钱业务是通过用户直接去金库取钱而完成

 // 取钱业务
 class Take {
     num: number
     type: string
     constructor(type: string, num: number) {
         this.type = type
         this.num = num
     }
 }
 
 // 你直接金库取钱
 let money50 = new Take('RMB', 50)

在银行开设一段时间后,发现了两个问题:

  • 遇到不诚实的用户,本来他的银行卡里面只有50人民币,但是他却在金库取了50美元,银行亏损验证
  • 遇到一些不熟悉取钱业务的用户,就根本不知道如何去取钱

为什么解决这两个问题,银行招收了一些业务员,专门为用户办理取钱业务

 // 取钱业务
 class Take {
     num: number
     type: string
     constructor(type: string, num: number) {
         this.type = type
         this.num = num
     }
 }
 
 // 业务员
 class Salesman {
     public static takeMoney(type, num): Take {
         if (type === 'RMB') {
             return new Take('RMB', num)
         } else if (type === 'USD') {
             return new Take('USD', num)
         } else {
             return new Take('RMB', num)
         }
     }
 }
 
 let money50 = Salesman.takeMoney('USD', 50)

在业务员的不懈努力下,不仅防止了用户乱取钱,还帮助许多不熟悉取钱业务的用户取钱,在这里业务员就是工厂类,他的存在就是为了控制金库类的创建和方便用户创建金库类

设计模式的原则是封装与隔离,简单工厂模式通过工厂类隔离类创建者和类,将类的创建逻辑封装在工厂类中,在例子中,Salesman类就是工厂类,静态方法takeMoney承担了创建了Take类的职责

简单工厂模式的优点其实已经可以不言而喻了

  • 保护类不被开发者胡乱创建(创建Take类时,第一个参数本应传递RMB,开发者却传递USD,想多取钱)
  • 方便开发者创建类(如果Take类需要接受100参数,那开发者不可能记住这100参数呀,而通过takeMoney提前设置好这100个参数,开发者就可以方便创建对象了)

工厂方法模式

场景:银行现在不止需要开设取钱业务,还需要开设存钱、贷款业务

// 取钱业务
class Take {
    num: number
    type: string
    constructor(type: string, num: number) {
        this.type = type
        this.num = num
    }
}

// 贷款业务
class Loan {
    num: number
    type: string
    constructor(type: string, num: number) {
        this.type = type
        this.num = num
    }
}

// 业务员
class Salesman {
    public static takeMoney(businessType, type, num): Take | Loan {
        if (businessType === 'Take') {
            if (type === 'RMB') {
                return new Take('RMB', num)
            } else if (type === 'USD') {
                return new Take('USD', num)
            } else {
                return new Take('RMB', num)
            }
        } else if (businessType === 'Loan') {
            if (type === 'RMB') {
                return new Loan('RMB', num)
            } else if (type === 'USD') {
                return new Loan('USD', num)
            } else {
                return new Loan('RMB', num)
            }
        }
    }
}

let money50 = Salesman.takeMoney('Take', 'USD', 50)

银行营业没几周,所有业务员都抗议,又出现问题了

  • 他们觉得自己太累了,需要记住银行所以的业务,根本忙不过来
  • 新增业务时,需要培训所以的业务员,变动很大

讲过会议商讨,决定根据业务的不同而设立不同的部门,将业务员分到不同的部门下面,再设立协助岗位(拿到用户的业务需求,然后去对应的部门办理业务)

interface Business {
    num: number
    type: string
}

interface BusinessConstructor {
    new(type: string, num: number): Business;
}

// 取钱业务
class Take implements Business {
    num: number
    type: string
    constructor(type: string, num: number) {
        this.type = type
        this.num = num
    }
}

// 贷款业务
class Loan implements Business {
    num: number
    type: string
    constructor(type: string, num: number) {
        this.type = type
        this.num = num
    }
}

// 取钱部门
class TakeDepartment extends Take {
    constructor(type, num) {
        if (type === 'RMB') {
            super('RMB', num)
        } else if (type === 'USD') {
            super('USD', num)
        } else {
            super('RMB', num)
        }
    }
}

// 贷款部门
class LoanDepartment extends Take {
    constructor(type, num) {
        if (type === 'RMB') {
            super('RMB', num)
        } else if (type === 'USD') {
            super('USD', num)
        } else {
            super('RMB', num)
        }
    }
}

// 协助岗位
class Salesman {
    public static takeMoney(businessType, ...args: ConstructorParameters<BusinessConstructor>): Take | Loan {
        if (businessType === 'Take') {
            return new TakeDepartment(...args)
        } else if (businessType === 'Loan') {
            return new LoanDepartment(...args)
        }
    }
}

let money50 = Salesman.takeMoney('Take', 'USD', 50,)

通过用户员和协助岗位的共通协做,业务实施的十分顺利,每个部门都只需要做自己的事情,而不需要关心其他部门的业务,大大减少了业务员的压力,而且再新增其他业务时,只需要添加对应的业务部门就可以了

工厂方法模式的核心是工厂类负责找到目标类的子类,实际创建对象的过程推迟由目标类的子类完成Salesman类从业务员到协助岗位,实际上是,Salesman类的工作中心由具体业务到寻找部门的过程,起着中间层的作用,而LoanDepartmentTakeDepartment这些部门子类则担起了完成业务的职责

工厂方法模式的优点也是很明显的

  • 承上启下,利于业务扩建(以后再新增存钱业务,只用增加对应的部门和培训协助岗位就可以了)
  • 单一职能,把具体业务分配到不同的子类中(取钱部门和贷款部门业务独立)

抽象工厂模式

场景:为了拓展义务,高层决定在每个部门都新增业务

在工厂方法模式中,一个部门只能实现一种业务,为了实现多种业务,只能放弃继承

interface Business { }

// 商业贷业务
class CommercialLoan implements Business { }

// 贷款业务
class PersonalLoan implements Business { }

// 贷款部门
class LoanDepartment {
    constructor(businessType) {
        if (businessType == 'Commercial') {
            return new CommercialLoan()
        } else if (businessType == 'Personal') {
            return new PersonalLoan()
        }
    }
}

// 协助岗位
class Salesman {
    public static takeMoney(departmentType, businessType) {
        if (departmentType === 'Loan') {
            return new LoanDepartment(businessType)
        }
    }
}

let loan = Salesman.takeMoney('Loan', 'Commercial')

几周过后,用户和协助人员都不干了

  • 用户去贷款部门办理多个业务,还需要找协助人员两次,客户觉得很麻烦,还不如自己去找
  • 协助人员每次去完成业务,先找部门,再找不同的业务,腿都跑断

业务完成耗时,流程复杂,董事长学过设计模式,他宣布以后协助人员只负责给用户指路,让用户自己去完成业务

interface Business { }

// 商业贷业务
class CommercialLoan implements Business { }

// 贷款业务
class PersonalLoan implements Business { }

// 贷款部门
class LoanDepartment {
    constructor(businessType) {
        if (businessType == 'Commercial') {
            return new CommercialLoan()
        } else if (businessType == 'Personal') {
            return new PersonalLoan()
        }
    }
}

// 协助岗位
class Salesman {
    public static takeMoney(departmentType) {
        if (departmentType === 'Loan') {
            return LoanDepartment
        }
    }
}

//贷款部门
let Loan = Salesman.takeMoney('Loan')
// 商业贷业务
let commercial = new Loan('Commercial')
// 贷款业务
let personal = new Loan('Personal')

协助员和用户都很开心了,用户可以同时完成多个业务,协助员也可以当一个安静的美男子!!!

抽象工厂模式的核心是把创建类的权利给用户,工厂只负责给用户提供需要的类Salesman类的工作越来越轻松了,每个类都有自己的功能,这很符合单一职责原则

抽象工厂模式的优点

  • 开发者的权利增大,让开发者可以自由完成不同的业务

  • 工厂类的功能缩小

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 19 天,点击查看活动详情