工厂模式是一种用来创建对象的设计模式。我们不暴露对象创建的逻辑,而是将逻辑封装在一个函数内,那么这个函数可以成为工厂。工厂模式根据抽象程度的不同可以分为:1.简单工厂 2.工厂方法 3.抽象工厂
简单工厂
简单工厂模式十分好理解,它属于类的创建型模式,又叫静态工厂方法模式。通过专门定义一个工厂类来负责创建其他类的实例,被创建的实例通常都具有共同的父类,也就是说创建出来的示例全都是此构造函数实例化出来的
function bookShop () {
var book = new Object();
book.price = '暂无标价';
if (name === 'JS编程') {
book.price = '10';
book.bookFunctio=()=>{}
}
if (name === 'vue.3.0') {
book.price = '20';
book.bookFunctio=()=>{}
}
if (name === '大数据可视化') {
book.price = '30';
book.bookFunctio=()=>{}
}
return book;
}
var book1 = bookShop('JS编程');
var book2 = bookShop('vue.3.0');
var book3 = bookShop('大数据可视化');
拿到的数据肯定都是bookShop构造的示例,实例中有不同的price,和不同的函数,这就是简单的工厂模式,也是最最基础的工厂模式
优点
:
工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
客户端无需知道所创建具体产品的类名,只需知道参数即可。
也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类。
缺点
:
简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂 简单工厂模式使用了 static工厂方法,造成工厂角色无法形成基于继承的等级结构。
工厂方法模式
工厂方法模式中,核心的工厂类不再负责所以产品的创建,而是将具体的创建工作交给子工厂来做,这一点是网上有些例子讲的不是太清楚,在普遍意义的编程语言中,这个的核心就是
继承
,用子工厂
继承
父工厂的属性,且实例化的时候
实例化子工厂
,产生的实例也是不同子工厂的实例,但是前端中的
class
实际上是语法糖,我们也可以按照继承来写,但是我看到的是我们可以把子工厂放
prototype
上,这样工厂来生产对象的时候从表面上来看还是从父工厂来产生的,与prototype原型链有关的暂时不做赘述
var BookShop = function (name) {
// 如果外部直接调用了BookShop而不是new关键字调用,则返回new BookShop调用,否则直接调用
// 这个产品类创建实例返给外部
//if (this instanceof BookShop) {
var bookObj = new this[name]()
return bookObj
// } else {
// return new BookShop(name)
// }
}
BookShop.prototype = {
Programme: function () {
this.books = ['css世界', 'JS高级编程', 'ES6入门教程']
},
//Science: function () {
// this.books = ['人与自然', '大自然的奥秘', '走进科学']
//},
//Society: function () {
// this.books = ['精神小伙修炼手册', '摇花手', '豆豆鞋']
//}
}
var programme = new BookShop('programme');
//var science = BookShop('science');
//var society = BookShop('society');
如果外部直接调用了BookShop而不是new关键字调用,则返回new BookShop调用,否则直接调用
,这句话,跟工厂方法模式没什么关系,主要是兼容了工厂的实例化没有用
new
关键字,我注释掉了重复或者跟工厂方法模式本身无关的地方,只看最简单的
1.
子工厂的挂载
,
2.父工厂通过接收参数方式来使用不同的
子工厂创建实例
,得到了不同的构造函数所创造的实例,这就是工厂方法模式,new的都是同一个构造函数,得到的却不是相同的实例
优点
:
拥有工厂方法的优点
可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
当需要产品族时,抽象工厂可以保证客户端始终只使用同一个产品的产品组。
抽象工厂增强了程序的可扩展性,当增加一个新的产品族时,不需要修改原代码,满足开闭原则。
缺点
当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。增加了系统的抽象性和理解难度。
抽象工厂模式
抽象工厂模式相对来说比较复杂,想要了解抽象工厂模式,必须得知道什么是抽象类
抽象类
- 什么是抽象类,就是在父类中调用一个未定义的方法,这个方法在子类中必须被实现。
-
什么是抽象方法,就是一个已定义但是没有实现的方法,这个东西如果有计算机基础的人会知道,在c++和java中有
接口
,比较类似
Object.extend = function(des,source){
for(p in source){
des[p] = source[p];
}
return des;
};
Object.prototype.extend = function(object){
return Object.extend.apply(this,[this,object]);
};
function BaseClass(){};
BaseClass.prototype = {
initialize:function(name,age){
this.name = name;
this.age = age;//调用了一个抽象方法
this.oninit();
},
//抽象方法是一个空方法,由派生类实现
oninit:function(){}
};
function ClassA(){};
ClassA.prototype = (new BaseClass()).extend({
oninit:function(){
alert(this.name + ' : ' + this.age);
}
});
var obj = new ClassA();
obj.initialize('Tom',22);
如果子类不是抽象类的话,那么在子类中必须重写抽象父类的抽象方法,简单来讲就是不管他是啥,我先定义好,谁想来继承,就要把这个方法给实现了
抽象工厂
- 核心问题,在于继承,抽象工厂的能力就在于不同的工厂去继承抽象工厂
let agency = function(subType, superType) {
//判断抽象工厂中是否有该抽象类
if(typeof agency[superType] === 'function') {
function F() {};
//继承父类属性和方法
F.prototype = new agency[superType] ();
//将子类的constructor指向子类
subType.constructor = subType;
//子类原型继承父类
subType.prototype = new F();
} else {
throw new Error('抽象类不存在!')
}
}
如上:拥有继承抽象类的能力,叫抽象工厂
代码也比较容易理解,通俗的来讲就是,把父类的一身本领全部挂载到一个空的类的prototype上,然后把子类的constructor指向子类,然后再把挂载到空的类的一身本领挂载给子类,这样子类就从父类那里学到了父类的一身本领
agency.mouseShop = function() {
this.type = '鼠标';
}
agency.mouseShop.prototype = {
getName: function() {
return new Error('抽象方法不能调用');
}
}
如上:创建一个抽象类等待继承
function mouse(name) {
this.name = name;
this.item = ['买我,我线长',"玩游戏贼溜"]
}
//抽象工厂实现鼠标类的继承
agency(mouse, 'mouseShop');
//子类中重写抽象方法
mouse.prototype.getName = function() {
return this.name;
}
如上:普通类继承抽象子类,并重写抽象子类的方法
//实例化普通类
let mouseA = new mouse('联想');
console.log(mouseA.getName(), mouseA.type); //联想 鼠标
如上:实例化普通类,使用类的方法及属性
总结:
1.前两种工厂看起来十分简单,但是抽象工厂理念对于有些人可能难以理解,为啥要创建一个这样的工厂,其实简单的例子不能看出来工厂的方便之处,但是我们遐想一下,如果相同之处非常多,或者说多种类多种工厂,有很多的相似之处,那我们一个总工厂的必要性就出来了,多个普通类都可以更简便的书写,因为他们的共同之处都在
子抽象类
中已经命名定义好了,我们继承之后之专注自己的逻辑以及代码就好
2.这是一种思维,并不是一种照搬的开发模式,工厂的思维在某些情境下是十分有用的,特别是较为复杂较为繁琐的地方,能让我们的开发逻辑更清晰明白,也更好分析代码逻辑,
不是啥时候都适合使用工厂模式的嗷
,因地制宜因材施教