工廠模式是用來建立對象的一種最經常使用的設計模式。根據抽象程度的不一樣能夠分爲:簡單工廠模式,工廠方法模式 和 抽象工廠模式。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 {}
複製代碼
當系統須要新增一個產品族時,只須要增長新的工廠類便可,無需修改源代碼;
可是若是須要產品族中增長一個新種類的產品時,則全部的工廠類都須要修改
不管是 簡單工廠模式、工廠方法模式 仍是 抽象工廠模式,它們本質上都是將不變的部分提取出來,將可變的部分留做接口,以達到最大程度上的 複用。究竟用哪一種設計模式更適合,這要根據具體的業務需求來決定。不要學會了用刀,就見什麼都砍。
文中若有遺漏或者錯誤請各位大神指點,不勝感激。