【設計模式】前端這樣學習設計模式-工廠模式

工廠模式

工廠模式是用來建立對象的一種最經常使用的設計模式。根據抽象程度的不一樣能夠分爲:簡單工廠模式工廠方法模式抽象工廠模式html

簡單工廠模式

定義

簡單工廠模式,又稱爲靜態工廠方法模式。由一個工廠對象決定建立出哪種產品類的實例。前端

類圖

我決定不幹前端了,回家開了個星巴克咖啡廳,顧客到個人咖啡廳點一杯咖啡,告訴我須要哪一種咖啡,我來根據顧客的決定建立咖啡。因爲是小本生意,所有由我親力親爲。react

微信截圖_20210617171928.png

咖啡類:Coffeeweb

子類:美式咖啡(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);
};
複製代碼

工廠方法模式

定義

工廠方法模式,又稱多態性工廠模式。在工廠方法模式中,核心的工廠類再也不負責全部的產品的建立,而是將具體建立的工做交給工廠子類去作。

工廠方法模式的本意是將實際建立對象的工做推遲到子類中,這樣核心類就變成了抽象類。咱們能夠將工廠方法看做是一個實例化對象的工廠類。

類圖

開店就是比干前端掙錢,隨着我星巴克咖啡店規模的擴大,品種的增長,而且個人顧客也愈來愈多,這時我一我的就已經忙不過來了,我決定安心當老闆,躺平收錢。因而我顧了幾個服務員,每一個服務員負責 一個品種 的製做。顧客在我這下單,再由我分配給對應的服務員進行生產。

微信截圖_20210622145249.png

與簡單工廠的區別

在簡單工廠模式中,是由工廠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' });
複製代碼

抽象工廠模式

定義

抽象工廠模式,又稱其餘工廠的工廠。能夠向客戶端提供一個接口,使客戶端在沒必要指定產品的具體的狀況下,建立多個產品族中的產品對象

先借助一個圖來理解產品族和產品等級

個人咖啡廳一共有三種咖啡,美式,拿鐵,卡布奇諾。因爲我明智的放棄了前端,選擇了星巴克,賺了不少錢,這個時候我決定再開一家咖啡廳,名字叫瑞幸。咖啡的品類和星巴克同樣。

產品等級:即產品的繼承結構,能夠理解爲不一樣家的同一產品

產品族:指由同一個工廠生產的,位於不一樣產品等級結構中的一組產品,能夠理解爲同一家的不一樣產品,是一組相關或相互依賴的對象。

abstractfactory2.png

組成角色

抽象工廠: 提供了建立產品的接口,包含多個建立產品的抽象方法(咖啡工廠)

具體工廠: 實現抽象工廠定義的接口,完成某個具體產品的建立(星巴克工廠和瑞幸工廠)

抽象產品:產品的定義,通常有多少抽象產品,抽象工廠中就包含多少個建立產品的方法(美式咖啡,拿鐵咖啡,卡布奇諾咖啡)

具體產品: 抽象產品的實現類(星巴克美式咖啡,瑞幸拿鐵咖啡)

類圖

咖啡工廠(CafeFactory),包含製做三種咖啡的抽象方法,子類星巴克工廠和瑞幸工廠分別生產各自的美式咖啡,拿鐵咖啡,卡布奇諾咖啡。

微信截圖_20210622184007.png

與工廠方法模式的區別

工廠方法模式針對的是同一類或同等級產品,而抽象工廠模式針對的是多種類的產品設計

代碼

//抽象類能夠繼承抽象類
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 {}
複製代碼

優勢

當系統須要新增一個產品族時,只須要增長新的工廠類便可,無需修改源代碼;

缺點

可是若是須要產品族中增長一個新種類的產品時,則全部的工廠類都須要修改

總結

不管是 簡單工廠模式工廠方法模式 仍是 抽象工廠模式,它們本質上都是將不變的部分提取出來,將可變的部分留做接口,以達到最大程度上的 複用。究竟用哪一種設計模式更適合,這要根據具體的業務需求來決定。不要學會了用刀,就見什麼都砍。

文中若有遺漏或者錯誤請各位大神指點,不勝感激。

參考

web前端-js設計模式

三大工廠模式的優缺點

相關文章
相關標籤/搜索