工厂模式是用来建立对象的一种最经常使用的设计模式。根据抽象程度的不一样能够分为:简单工厂模式,工厂方法模式 和 抽象工厂模式。html
简单工厂模式,又称为静态工厂方法模式。由一个工厂对象决定建立出哪种产品类的实例。前端
我决定不干前端了,回家开了个星巴克咖啡厅,顾客到个人咖啡厅点一杯咖啡,告诉我须要哪一种咖啡,我来根据顾客的决定建立咖啡。因为是小本生意,所有由我亲力亲为。react
咖啡类:Coffee
web
子类:美式咖啡(AmericanCoffee)
、拿铁咖啡(LatteCoffee)
、卡布奇诺咖啡(CappuccinoCoffee)
。设计模式
//抽象类只能用于继承 咖啡类
abstract class Coffee {
/* 在参数中加public修饰符能够达到简写的目的 不用声明name:string 构造函数中不用this.name=name */
constructor(public name: string) {}
}
//子类 美式咖啡
class AmericanCoffee extends Coffee {}
//子类 拿铁咖啡
class LatteCoffee extends Coffee {}
//子类 卡布奇诺咖啡
class CappuccinoCoffee extends Coffee {}
//创建咖啡工厂 简单工厂 根据传入的参数返回不一样子类的实例
class CafeFactory {
static order(name: string) {
switch (name) {
case 'American':
return new AmericanCoffee('美式咖啡');
case 'Latte':
return new LatteCoffee('拿铁咖啡');
case 'Cappuccino':
return new CappuccinoCoffee('卡布奇诺咖啡');
default:
throw new Error('没有此种咖啡');
}
}
}
//调用工厂函数测试一下
console.log(CafeFactory.order('American')); //AmericanCoffee {name: "美式咖啡"}
console.log(CafeFactory.order('Latte')); //LatteCoffee {name: "拿铁咖啡"}
console.log(CafeFactory.order('Cappuccino')); //CappuccinoCoffee {name: "卡布奇诺咖啡"}
console.log(CafeFactory.order('meinianda')); //Uncaught Error: 没有此种咖啡
复制代码
这就是一个简单工厂,根据传入的参数,返回不一样子类的实例。数组
只须要一个正确的参数,就能够获取到你所须要的对象,而无需知道其建立的具体细节。微信
若是产品的种类很是多switch case
的判断会变得很是多,这个函数就会变的很是臃肿而且难以维护。markdown
函数内包含了全部对象的建立逻辑和判断逻辑的代码,,若是要增长或删除一个产品种类,就须要修改判断逻辑代码,不符合开放—封闭原则app
因此,简单工厂只能做用于建立的对象数量较少,对象的建立逻辑不复杂时使用。dom
jQuery
源码中的$(selector)
就是一个简单工厂
$('div')
和new $('div')
哪一个好用,很显然直接$(div)
更方便 ,因此这里使用简单工厂模式,简略了new
的过程
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.prototype.init( selector, context );
};
复制代码
仿照jQuery
实现一个简单工厂函数
//联合类型
interface jQuery {
[index: number]: any;
}
class jQuery {
length: number;
constructor(selector: string) {
//获取dom元素 使用Array.from将类数组转成数组
let elements = Array.from(document.querySelectorAll(selector));
let length = elements ? elements.length : 0;
this.length = length;
for (let i = 0; i < length; i++) {
this[i] = elements[i];
}
}
html(htmlText: string | undefined) {
//若是传参就是赋值,不然就是取值
if (htmlText) {
for (let i = 0; i < this.length; i++) {
this[i].innerHTML = htmlText;
}
} else {
return this[0].innerHTML;
}
}
}
interface Window {
$: any;
}
//简单工厂就是函数里返回类的实例
window.$ = function (selector: string) {
return new jQuery(selector);
};
复制代码
工厂方法模式,又称多态性工厂模式。在工厂方法模式中,核心的工厂类再也不负责全部的产品的建立,而是将具体建立的工做交给工厂子类去作。
工厂方法模式的本意是将实际建立对象的工做推迟到子类中,这样核心类就变成了抽象类。咱们能够将工厂方法看做是一个实例化对象的工厂类。
开店就是比干前端挣钱,随着我星巴克咖啡店规模的扩大,品种的增长,而且个人顾客也愈来愈多,这时我一我的就已经忙不过来了,我决定安心当老板,躺平收钱。因而我顾了几个服务员,每一个服务员负责 一个品种 的制做。顾客在我这下单,再由我分配给对应的服务员进行生产。
在简单工厂模式中,是由工厂Factory
来建立产品的。
在工厂方法模式中,再也不由工厂Factory
来建立产品,而是先建立具体的工厂,而后由具体的工厂来建立产品。
//Description:工厂方法模式 把建立产品的工做交由具体工厂类来实现
//抽象类只能用于继承 咖啡类
abstract class Coffee {
constructor(public name: string) {}
}
//子类 美式咖啡
class AmericanCoffee extends Coffee {}
//子类 拿铁咖啡
class LatteCoffee extends Coffee {}
//子类 卡布奇诺咖啡
class CappuccinoCoffee extends Coffee {}
//抽象类 咖啡工厂类
abstract class CafeFactory {
//抽象方法 不须要实现
abstract createCoffee(): Coffee;
}
//美式咖啡工厂
class AmericanFactory extends CafeFactory {
createCoffee() {
return new AmericanCoffee('美式咖啡');
}
}
//拿铁咖啡工厂
class LatteFactory extends CafeFactory {
createCoffee() {
return new LatteCoffee('拿铁咖啡');
}
}
//卡布奇诺咖啡工厂
class CappuccinoFactory extends CafeFactory {
createCoffee() {
return new CappuccinoCoffee('卡布奇诺咖啡');
}
}
let americanFactory = new AmericanFactory();
console.log(americanFactory.createCoffee()); //AmericanCoffee {name: "美式咖啡"}
let latteFactory = new LatteFactory();
console.log(latteFactory.createCoffee()); //LatteCoffee {name: "拿铁咖啡"}
let cappuccinoFactory = new CappuccinoFactory();
console.log(cappuccinoFactory.createCoffee()); //CappuccinoCoffee {name: "卡布奇诺咖啡"}
复制代码
也能够结合简单工厂模式简化代码
//结合简单工厂模式
class Factory {
static order(name: string) {
switch (name) {
case 'American':
return new AmericanFactory().createCoffee();
case 'Latte':
return new LatteFactory().createCoffee();
case 'Cappuccino':
return new CappuccinoFactory().createCoffee();
default:
throw new Error('没有此种咖啡');
}
}
}
//调用工厂函数测试一下
console.log(Factory.order('American')); //AmericanCoffee {name: "美式咖啡"}
console.log(Factory.order('Latte')); //LatteCoffee {name: "拿铁咖啡"}
console.log(Factory.order('Cappuccino')); //CappuccinoCoffee {name: "卡布奇诺咖啡"}
console.log(Factory.order('meinianda')); //Uncaught Error: 没有此种咖啡
复制代码
工厂方法模式每一个具体工厂类只完成单一任务,代码简洁,若是要增长一个产品种类,只须要增长一个产品工厂,符合 开放—封闭原则,有很是良好的 扩展性。
假如某个具体产品类须要进行必定的修改,极可能须要修改对应的工厂类。当同时须要修改多个产品类的时候,对工厂类的修改会变得至关麻烦。
每增长一个产品,相应的也要增长一个工厂,会加大额外的开发量。
仿照react
源码,一个用来生成dom
的工厂方法
function createElement(type: any, config: any) {
//this绑定为null 第一个参数绑定为type
return { type, props: config };
}
function createFactory(type) {
//源码中没有用到this,因此this绑定为null
const factory = createElement.bind(null, type);
return factory;
}
let factory = createFactory('h1');
let element = factory({ id: 'h1', className: 'title' });
复制代码
抽象工厂模式,又称其余工厂的工厂。能够向客户端提供一个接口,使客户端在没必要指定产品的具体的状况下,建立多个产品族中的产品对象
个人咖啡厅一共有三种咖啡,美式,拿铁,卡布奇诺。因为我明智的放弃了前端,选择了星巴克,赚了不少钱,这个时候我决定再开一家咖啡厅,名字叫瑞幸。咖啡的品类和星巴克同样。
产品等级:即产品的继承结构,能够理解为不一样家的同一产品。
产品族:指由同一个工厂生产的,位于不一样产品等级结构中的一组产品,能够理解为同一家的不一样产品,是一组相关或相互依赖的对象。
抽象工厂: 提供了建立产品的接口,包含多个建立产品的抽象方法(咖啡工厂)
具体工厂: 实现抽象工厂定义的接口,完成某个具体产品的建立(星巴克工厂和瑞幸工厂)
抽象产品:产品的定义,通常有多少抽象产品,抽象工厂中就包含多少个建立产品的方法(美式咖啡,拿铁咖啡,卡布奇诺咖啡)
具体产品: 抽象产品的实现类(星巴克美式咖啡,瑞幸拿铁咖啡)
咖啡工厂(CafeFactory)
,包含制做三种咖啡的抽象方法,子类星巴克工厂和瑞幸工厂分别生产各自的美式咖啡,拿铁咖啡,卡布奇诺咖啡。
工厂方法模式针对的是同一类或同等级产品,而抽象工厂模式针对的是多种类的产品设计
//抽象类能够继承抽象类
abstract class Coffee {}
//抽象产品
abstract class AmericanCoffee extends Coffee {}
abstract class LatteCoffee extends Coffee {}
abstract class CappuccinoCoffee extends Coffee {}
//具体产品的个数 = 产品族 * 产品等级
class StarBucksAmericanCoffee extends AmericanCoffee {}
class StarBucksLatteCoffee extends LatteCoffee {}
class StarBucksCappuccinoCoffee extends CappuccinoCoffee {}
class LuckinAmericanCoffee extends AmericanCoffee {}
class LuckinLatteCoffee extends LatteCoffee {}
class LuckinCappuccinoCoffee extends CappuccinoCoffee {}
//抽象工厂 须要三个抽象方法
abstract class CafeFactory {
//抽象方法 建立美式咖啡
abstract createAmericanCoffee(): AmericanCoffee;
//抽象方法 建立拿铁咖啡
abstract createLatteCoffee(): LatteCoffee;
//抽象方法 建立卡布奇诺咖啡
abstract createCappuccinoCoffee(): CappuccinoCoffee;
}
//具体工厂 星巴克
class StarBucksCafeFactory extends CafeFactory {
//具体方法 建立星巴克美式咖啡
createAmericanCoffee() {
return new StarBucksAmericanCoffee();
}
//具体方法 建立星巴克拿铁咖啡
createLatteCoffee() {
return new StarBucksLatteCoffee();
}
//具体方法 建立星巴克卡布奇诺咖啡
createCappuccinoCoffee() {
return new StarBucksCappuccinoCoffee();
}
}
//具体工厂 瑞幸
class LuckinCafeFactory extends CafeFactory {
//具体方法 建立星巴克美式咖啡
createAmericanCoffee() {
return new LuckinAmericanCoffee();
}
//具体方法 建立星巴克拿铁咖啡
createLatteCoffee() {
return new LuckinLatteCoffee();
}
//具体方法 建立星巴克卡布奇诺咖啡
createCappuccinoCoffee() {
return new LuckinCappuccinoCoffee();
}
}
//建立瑞幸工厂
let luckinCafeFactory = new LuckinCafeFactory();
//建立瑞幸的美式咖啡
console.log(luckinCafeFactory.createAmericanCoffee()); //LuckinAmericanCoffee {}
复制代码
当系统须要新增一个产品族时,只须要增长新的工厂类便可,无需修改源代码;
可是若是须要产品族中增长一个新种类的产品时,则全部的工厂类都须要修改
不管是 简单工厂模式、工厂方法模式 仍是 抽象工厂模式,它们本质上都是将不变的部分提取出来,将可变的部分留做接口,以达到最大程度上的 复用。究竟用哪一种设计模式更适合,这要根据具体的业务需求来决定。不要学会了用刀,就见什么都砍。
文中若有遗漏或者错误请各位大神指点,不胜感激。