之前對設計模式瞭解的不是很多,現在以前端爲切入點來學習設計模式,在學習的過程中會借鑑其他人的博客和代碼,會在文章末尾標註來源出處
1. 簡單工廠
根據參數的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。
//汽車類
class Car {
constructor({ doors, state, color }) {
//默認值
this.doors = doors || 4;
this.state = state || 'brand new';
this.color = color || 'silver';
}
}
// 卡車類
class Truck {
constructor({ state, wheelSize, color }) {
this.state = state || 'used';
this.wheelSize = wheelSize || 'large';
this.color = color || 'blue';
}
}
// 簡單工廠
class VehicleFactory {
constructor() {
this.vehicleClass = Car;
}
// 工廠方法 創建一個車型實例
createVehicle(options) {
switch (options.vehicleType) {
case 'car':
this.vehicleClass = Car;
break;
case 'truck':
this.vehicleClass = Truck;
break;
// VehicleFactory.prototype.vehicleClass (Car)
}
return new this.vehicleClass(options);
}
}
const carFactory = new VehicleFactory();
const car = carFactory.createVehicle({
vehicleType: 'car',
color: 'yellow',
doors: 6,
});
適用環境
在以下情況下可以使用簡單工廠模式:
工廠類負責創建的對象比較少:由於創建的對象較少,不會造成工廠方法中的業務邏輯太過複雜。
客戶端只知道傳入工廠類的參數,對於如何創建對象不關心:客戶端既不需要關心創建細節,甚至連類名都不需要記住,只需要知道類型所對應的參數。
工廠模式的優點:
- 簡單工廠模式通過這種做法實現了對責任的分割,它提供了專門的工廠類用於創建對象
- 把所有實例化代碼集中在一起,簡化所用的類或在運行期間動態選擇所用類的工作
- 弱化對象間的耦合 防止代碼重複 在一個方法中進行類的實例化,可以消除重複代碼,
- 用一個對接口的調用取代一個具體的實現,有助於創建模塊化代碼
工廠模式的缺點:
- 簡單工廠模式最大的問題在於工廠類的職責相對過重,增加新的產品需要修改工廠類的判斷邏輯,這一點與開閉原則是相違背的。
- 由於工廠類集中了所有產品創建邏輯,一旦不能正常工作,整個系統都要受到影響。
- 使用簡單工廠模式將會增加系統中類的個數,在一定程序上增加了系統的複雜度和理解難度。
- 系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,在產品類型較多時,有可能造成工廠邏輯過於複雜,不利於系統的擴展和維護。
- 簡單工廠模式由於使用了靜態工廠方法,造成工廠角色無法形成基於繼承的等級結構。
2. 抽象工廠
/**
* 披薩原料工廠 接口
* @class PizzaIngredientFactory
*/
class PizzaIngredientFactory {
//該接口的方法必須覆蓋重寫,不允許子類繼承調用
createDough() {
throw new Error("This method must be overwritten!");
}
createSauce() {
throw new Error("This method must be overwritten!");
}
createCheese() {
throw new Error("This method must be overwritten!");
}
createVeggies() {
throw new Error("This method must be overwritten!");
}
createPepperoni() {
throw new Error("This method must be overwritten!");
}
createClam() {
throw new Error("This method must be overwritten!");
}
}
/**********食品材料類start*************/
class FreshClams {}
class Garlic {}
class MarinaraSauce {}
class Mushroom {}
class Onion {}
class RedPepper {}
class ReggianoCheese {}
class SlicedPepperoni {}
class ThinCrustDough {}
/**********食品材料類end*************/
/**
* 紐約披薩原料工廠
* @class PizzaIngredientFactory
*/
class NewYorkPizzaIngredientFactory extends PizzaIngredientFactory {
createDough() {
return new ThinCrustDough();
}
createSauce() {
return new MarinaraSauce();
}
createCheese() {
return new ReggianoCheese();
}
createVeggies() {
return [new Garlic(), new Mushroom(), new RedPepper()];
}
createPepperoni() {}
createClam() {}
}
// 披薩接口
class Pizza {
constructor({
name = "",
dough = null,
sauce = null,
veggies = [],
cheese = null,
pepperoni = null,
clams = null
}) {
this.name = name;
this.dough = dough;
this.sauce = sauce;
this.veggies = veggies;
this.cheese = cheese;
this.pepperoni = pepperoni;
this.clams = clams;
}
prepare() {
throw new Error("This method must be overwritten!");
}
bake() {
console.log("Bake for 25 minutes at 350");
}
cut() {
console.log("Cutting the pizza into diagonal slices");
}
box() {
console.log("Place pizza in official PizzaStore box");
}
getName() {
return this.name;
}
setName(name) {
this.name = name;
}
}
/**************各種類披薩start**************/
class CheesePizza extends Pizza {
constructor(style, ingredientFactory) {
super({
name: style + " Cheese Pizza"
});
console.log(this.name);
this.ingredientFactory = ingredientFactory;
}
//
prepare() {
let ingredientFactory = this.ingredientFactory;
console.log("Preparing " + this.name);
this.dough = ingredientFactory.createDough();
this.sauce = ingredientFactory.createSauce();
this.cheese = ingredientFactory.createCheese();
}
}
class ClamPizza extends Pizza {
constructor(style, ingredientFactory) {
super({
name: style + " Clams Pizza"
});
this.ingredientFactory = ingredientFactory;
}
prepare() {
let ingredientFactory = this.ingredientFactory;
console.log("Preparing " + this.name);
this.dough = ingredientFactory.createDough();
this.sauce = ingredientFactory.createSauce();
this.cheese = ingredientFactory.createCheese();
this.clams = ingredientFactory.createClam();
}
}
class PepperoniPizza extends Pizza {
constructor(style, ingredientFactory) {
super({
name: style + " Pepperoni Pizza"
});
this.ingredientFactory = ingredientFactory;
}
prepare() {
let ingredientFactory = this.ingredientFactory;
console.log("Preparing " + this.name);
this.dough = ingredientFactory.createDough();
this.sauce = ingredientFactory.createSauce();
this.cheese = ingredientFactory.createCheese();
}
}
class VeggiePizza extends Pizza {
constructor(style, ingredientFactory) {
super({
name: style + " Veggie Pizza"
});
this.ingredientFactory = ingredientFactory;
}
prepare() {
let ingredientFactory = this.ingredientFactory;
console.log("Preparing " + this.name);
this.dough = ingredientFactory.createDough();
this.sauce = ingredientFactory.createSauce();
this.cheese = ingredientFactory.createCheese();
}
}
/**************各種類披薩end**************/
const PIZZAS = {
cheese: CheesePizza,
veggie: VeggiePizza,
clam: ClamPizza,
pepperoni: PepperoniPizza
};
/********披薩商店接口*********/
class PizzaStore {
createPizza() {
throw new Error("This method must be overwritten!");
}
//統一接口
orderPizza(type) {
let pizza = this.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
}
/********披薩商店*********/
class NewYorkPizzaStore extends PizzaStore {
//抽象方法
createPizza(type) {
let ingredientFactory = new NewYorkPizzaIngredientFactory();//
let PizzaConstructor = PIZZAS[type];//選擇具體的披薩類型
let pizza = null;
// 選擇好具體的披薩之後,調用披薩工廠方法選擇披薩的食品材料
if (PizzaConstructor) {
pizza = new PizzaConstructor("New York Style", ingredientFactory);
}
return pizza;
}
}
var oPizzaStore = new NewYorkPizzaStore();
oPizzaStore.orderPizza("cheese");
抽象工廠優點:
- 抽象工廠模式隔離了具體類的生成,使得客戶並不需要知道什麼被創建。應用抽象工廠模式可以實現高內聚低耦合的設計目的,因此抽象工廠模式得到了廣泛的應用。
- 當一個產品族中的多個對象被設計成一起工作時,它能夠保證客戶端始終只使用同一個產品族中的對象。這對一些需要根據當前環境來決定其行爲的軟件系統來說,是一種非常實用的設計模式。
- 增加新的具體工廠和產品族很方便,無須修改已有系統,符合“開閉原則”。
抽象工廠優點:
- 在添加新的產品對象時,難以擴展抽象工廠來生產新種類的產品,
- 開閉原則的傾斜性(增加新的工廠和產品族容易,增加新的產品等級結構麻煩)。
工廠模式的使用場景
- jquery $(“div”)
class jQuery{
constructor(selector){}
append(node){}
addClass(name){}
html(){}
}
window.$=function(selector){
return new jQuery(selector)
}
- React.createElement ()
class Vnode{
//...省略代碼
}
React.createElement = function(tag,attrs,children){
return new Vnode(tag, attrs, children);
}