前端设计模式——单例模式和工厂模式
作为一个前端新人,学习了设计模式以后,希望能从源头上,用浅显易懂的语言来解释它。当然不一定是正确的,只是我个人对设计模式的一点浅显理解。
创建型设计模式
创建型设计模式:故名思意,这些模式都是用来创建实例对象的。
单例模式:首先我们需要理解什么是单例。
单:指的是一个。
例:指的是创建的实例。
单例:指的是创建的总是同一个实例。也就是使用类创建的实例始终是相同的。
我们先看下面的一段代码:
class person{
constructor(){}
}
let p1 = new person();
let p2 = new person();
console.log(p1===p2) //false
上面这段代码,定义了一个person类,通过这个类创建了两个实例,我们可以看到最终这两个实例是不相等的。也就是说,通过同一个类得到的实例不是同一个(这本就是理所应当),但是如果我们想始终得到的是同一个实例,那么这就是**单例模式**。那么应该如何实现单例模式了:
想要实现单例模式,我们需要注意两点:
- 需要使用return。使用new的时候如果没有手动设置return,那么会默认返回this。但是,我们这里要使得每次返回的实例相同,也就是需要手动控制创建的对象,因此这里需要使用return。
- 我们需要每次return的是同一个对象。也就是说实际上在第一次实例的时候,需要把这个实例保存起来。再下一个实例的时候,直接return这个保存的实例。因此,这里需要用到闭包了。
代码实现如下:
(function(){
let instance = null;
return class{
constructor(){
if(!instance){
//第一次创建实例,那么需要把实例保存
instance = this;
}else{
return instance;
}
}
}
})()
let p3= new person();
let p4 = new person();
console.log(p3===p4) //true
从上面的代码中,我们可以看到在闭包中,使用instance变量来保存创建的实例,每次返回的都是第一次创建的实例。这样的话就实现了无论创建多少次,创建的都是同一个实例,这就是单例模式。
工厂模式
对于工厂来说,我们的印象可能是里面具有各种各样的模具,根据你想要的产品的模型,生产你需要的产品。比如说你请工厂帮你加工一个产品,你只需要告诉工厂你这个产品的结构,工厂就会有对应的模型帮你生产,你不需要去关心它具体是怎么加工的。同样工厂模式也是这样,(工厂模式也是创建型设计模式,用于创建实例对象的)你不需要自己去找对应的类来创建实例,你只需要告诉工厂类你要创建什么实例,他就会返回你需要的实例对象。
工厂模式根据抽象程度的不同,分为三种:
1. 简单工厂模式
2. 工厂方法模式
3. 抽象工厂模式
简单工厂模式
定义:定义一个工厂类,通过工厂函数,根据传入的参数不同,返回不同的实例。看下面的代码:
//学生类
class student{
constructor(name,age){
this.name = name;
this.age = age;
}
showname(){
console.log(this.name)
}
}
//老师类
class teacher{
constructor(name,age){
this.name = name;
this.age = age;
}
showname(){
console.log(this.name)
}
}
//警察类
class policeman{
constructor(name,age){
this.name = name;
this.age = age;
}
showname(){
console.log(this.name)
}
}
根据类创建对象
const s1 = new student('王小一',24);
const t1 = new teacher('李一老师',39);
const p1= new policeman('张一警官',40);
我们可以看到,上面代码中定义了三个类,学生类,老师类和警察类。而且它们具有相同的属性和方法。当我们需要创建学生实例时,我们调用学生类。当我们需要创建老师实例时,我们调用老师类,当我们需要创建警察实例,我们调用警察类。假设我们有更多的人物类,它们具有相同的功能,那么当我们需要创建实例的时候,我们同样需要调用相对应的类。事实上,这些类实现的都是相同的功能,那么我们可不可以把所有的创建这些人物实例都通过一个类来实现了。我们尝试将代码修改为如下:
//学生类
class student{
constructor(name,age){
this.name = name;
this.age = age;
}
showname(){
console.log(this.name)
}
}
//老师类
class teacher{
constructor(name,age){
this.name = name;
this.age = age;
}
showname(){
console.log(this.name)
}
}
//警察类
class policeman{
constructor(name,age){
this.name = name;
this.age = age;
}
showname(){
console.log(this.name)
}
}
//工厂类
class factory{
let obj = null;
//工厂函数
constructor(role,name,age){
switch(role){
case 'student':
obj = new student(name,age);
break;
case 'teacher':
obj = new teacher(name,age);
break;
case 'policeman':
obj = new policeman(name,age);
break;
}
}
return obj;
}
const s2 = new factory('student','王小二',25);
const t2 = new factory('teacher','李二老师',39);
const p2 = new factory('policeman','张二警官',40);
从上面的代码中,我们可以看到我们同样定义了学生类,老师类,警察类这三个类,但是我们创建实例时通过factory这个类,不再通过相对应的人物类了。这个factory类就是工厂类,我们观察工厂类的实现,发现里面是一个工厂函数(这里直接使用了constructor,也可以自己定义工厂函数),通过传递给工厂函数的参数不同,返回不同的实例。这就是简单工厂模式。
简单工厂模式总结:
实现:从上面的代码中我们可以知道,所谓简单工厂模式就是一个工厂类和一个工厂函数,通过传入参数的不同,返回不同的实例。
特点:1. 需要创建的类较少,因为需要根据传入的参数来判断返回的实例,如果类太多,那么就会导致逻辑复杂。2. 不需要关注实例的创建过程,只需要传入相对应的值即可。
适用场景:举一个生活中实际的使用场合,假如我们上体育课需要去拿篮球,足球和排球,我们可以自己去一个一个找对应的球(类似于上面通过自己来创建对象),也可以通过管理员,告诉管理员需要什么样的球,至于管理员是怎么找到这个相对应的球,就与我们不相关了。这个管理员就是工厂类。
缺点:从简单工厂模式的特点中我们可以知道,简单工厂模式适合于创建的类较少,一旦需要的类较多,逻辑就会复杂。而且一旦需要添加新的类,就得重新修改工厂类,这样显得非常不方便。
工厂方法模式
工厂方法模式是对简单工厂的进一步优化, 在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。也就是说每个对象都有一个与之对应的工厂。说的好像挺复杂,其实在我看来他就是解决简单工厂模式存在的不方便添加新的类,因为添加新的类以后需要修改工厂函数。而工厂方法模式就是解决这个问题,看下面的代码:
let factory = (function(){
let s = {
student(name,age){
this.name = name;
this.age = age;
return this;
},
teacher(name,age){
this.name = name;
this.age = age;
return this;
},
policeman(name,age){
this.name = name;
this.age = age;
return this;
},
//在这里添加新的类
doctor(name,age){
this.name = name;
this.age = age;
return this;
}
}
return class {
//工厂函数根据传进来的来的参数不同而不同。
constructor(type,name,age){
if(s.hasownproperty(type)){
return s[type].call(this,name,age)
}else{
throw new error(`不存在${type}类`)
}
}
}
})()
let s3 = new factory('student','王小三',25);
let t3 = new factory('teacher','李三老师',25);
let p3 = new factory('policeman','张三警官',28);
let d3 = new factory('doctor','杨医生',33);
从上面的代码中,我们可以看到,相比于简单工厂函数,工厂方法模式的工厂函数不是固定的,而是根据type不同而不同。当我们需要添加新的类时,只需要在s对象中添加实例即可,不需要修改工厂函数。这样的话就不会因为需要添加新的类,而修改过多的代码逻辑。这就是工厂方法模式。其实就是对简单工厂模式的优化而已。
推荐阅读
-
JavaScript设计模式精华摘抄(持续更新...)-考拉阅读前端团队-SegmentFault思否
-
单例模式正确使用方式
-
c#设计模式之单例模式的实现方式
-
wpf 单例模式和异常处理 (原发布 csdn 2017-04-12 20:34:12)
-
Java自学-类和对象 单例模式
-
Mybaits 源码解析 (十一)----- 设计模式精妙使用:静态代理和动态代理结合使用:@MapperScan将Mapper接口生成代理注入到Spring
-
设计模式之单例模式(懒汉式单例、饿汉式单例、登记式单例)
-
详解Java设计模式之单例模式
-
Java设计模式之抽象工厂模式
-
使用设计模式中的Singleton单例模式来开发iOS应用程序