# 工廠模式
工廠模式是另外一種關注對象創建概念的創建模式。它的領域中同其它模式的不同之處在于它并沒有明確要求我們使用一個構造器。取而代之,一個工廠能提供一個創建對象的公共接口,我們可以在其中指定我們希望被創建的工廠對象的類型。
試想一下,在我們被要求創建一種類型的UI組件時,我們就有一個UI工廠。并不是通過直接使用new操作符或者通過另外一個構造器來創建這個組件,我們取而代之的向一個工廠對象索要一個新的組件。我們告知工廠我們需要什么類型的組件(例如:“按鈕”,“面板”),而它會將其初始化,然后返回供我們使用。
如果創建過程相當復雜的話,那這會特別的有用,例如:如果它強烈依賴于動態因素或者應用程序配置的話。
這個模式的一些例子可以在UI庫里面找到,例如ExtJS, 用于創建對象或者組件的方法可以被做更深層次的子類。 下面使用用我們之前的那些代碼來做的一個例子,通過使用構造器模式邏輯來定義汽車。這個例子展示了Vehicle 工廠可以使用工廠模式來實現。
~~~
// Types.js - Constructors used behind the scenes
// A constructor for defining new cars
function Car( options ) {
// some defaults
this.doors = options.doors || 4;
this.state = options.state || "brand new";
this.color = options.color || "silver";
}
// A constructor for defining new trucks
function Truck( options){
this.state = options.state || "used";
this.wheelSize = options.wheelSize || "large";
this.color = options.color || "blue";
}
// FactoryExample.js
// Define a skeleton vehicle factory
function VehicleFactory() {}
// Define the prototypes and utilities for this factory
// Our default vehicleClass is Car
VehicleFactory.prototype.vehicleClass = Car;
// Our Factory method for creating new Vehicle instances
VehicleFactory.prototype.createVehicle = function ( options ) {
if( options.vehicleType === "car" ){
this.vehicleClass = Car;
}else{
this.vehicleClass = Truck;
}
return new this.vehicleClass( options );
};
// Create an instance of our factory that makes cars
var carFactory = new VehicleFactory();
var car = carFactory.createVehicle( {
vehicleType: "car",
color: "yellow",
doors: 6 } );
// Test to confirm our car was created using the vehicleClass/prototype Car
// Outputs: true
console.log( car instanceof Car );
// Outputs: Car object of color "yellow", doors: 6 in a "brand new" state
console.log( car );
~~~
### 方法1: 修改 VehicleFactory 實例使用 Truck 類
~~~
var movingTruck = carFactory.createVehicle( {
vehicleType: "truck",
state: "like new",
color: "red",
wheelSize: "small" } );
// Test to confirm our truck was created with the vehicleClass/prototype Truck
// Outputs: true
console.log( movingTruck instanceof Truck );
// Outputs: Truck object of color "red", a "like new" state
// and a "small" wheelSize
console.log( movingTruck );
~~~
### 方法2: 做 VehicleFactory 的子類用于創建一個工廠類生產 Trucks
~~~
function TruckFactory () {}
TruckFactory.prototype = new VehicleFactory();
TruckFactory.prototype.vehicleClass = Truck;
var truckFactory = new TruckFactory();
var myBigTruck = truckFactory.createVehicle( {
state: "omg..so bad.",
color: "pink",
wheelSize: "so big" } );
// Confirms that myBigTruck was created with the prototype Truck
// Outputs: true
console.log( myBigTruck instanceof Truck );
// Outputs: Truck object with the color "pink", wheelSize "so big"
// and state "omg. so bad"
console.log( myBigTruck );
~~~
## 何時使用工廠模式
當被應用到下面的場景中時,工廠模式特別有用:
* 當我們的對象或者組件設置涉及到高程度級別的復雜度時。
* 當我們需要根據我們所在的環境方便的生成不同對象的實體時。
* 當我們在許多共享同一個屬性的許多小型對象或組件上工作時。
* 當帶有其它僅僅需要滿足一種API約定(又名鴨式類型)的對象的組合對象工作時.這對于解耦來說是有用的。
## 何時不要去使用工廠模式
當被應用到錯誤的問題類型上時,這一模式會給應用程序引入大量不必要的復雜性.除非為創建對象提供一個接口是我們編寫的庫或者框架的一個設計上目標,否則我會建議使用明確的構造器,以避免不必要的開銷。
由于對象的創建過程被高效的抽象在一個接口后面的事實,這也會給依賴于這個過程可能會有多復雜的單元測試帶來問題。
## 抽象工廠
了解抽象工廠模式也是非常實用的,它的目標是以一個通用的目標將一組獨立的工廠進行封裝.它將一堆對象的實現細節從它們的一般用例中分離。
抽象工廠應該被用在一種必須從其創建或生成對象的方式處獨立,或者需要同多種類型的對象一起工作,這樣的系統中。
簡單且容易理解的例子就是一個發動機工廠,它定義了獲取或者注冊發動機類型的方式.抽象工廠會被命名為AbstractVehicleFactory.抽象工廠將允許像"car"或者"truck"的發動機類型的定義,并且構造工廠將僅實現滿足發動機合同的類.(例如:Vehicle.prototype.driven和Vehicle.prototype.breakDown)。
~~~
var AbstractVehicleFactory = (function () {
// Storage for our vehicle types
var types = {};
return {
getVehicle: function ( type, customizations ) {
var Vehicle = types[type];
return (Vehicle ? new Vehicle(customizations) : null);
},
registerVehicle: function ( type, Vehicle ) {
var proto = Vehicle.prototype;
// only register classes that fulfill the vehicle contract
if ( proto.drive && proto.breakDown ) {
types[type] = Vehicle;
}
return AbstractVehicleFactory;
}
};
})();
// Usage:
AbstractVehicleFactory.registerVehicle( "car", Car );
AbstractVehicleFactory.registerVehicle( "truck", Truck );
// Instantiate a new car based on the abstract vehicle type
var car = AbstractVehicleFactory.getVehicle( "car" , {
color: "lime green",
state: "like new" } );
// Instantiate a new truck in a similar manner
var truck = AbstractVehicleFactory.getVehicle( "truck" , {
wheelSize: "medium",
color: "neon yellow" } );
~~~
- 前言
- 簡介
- 什么是設計模式?
- 設計模式的結構
- 編寫設計模式
- 反模式
- 設計模式的分類
- 設計模式分類概覽表
- JavaScript 設計模式
- 構造器模式
- 模塊化模式
- 暴露模塊模式
- 單例模式
- 觀察者模式
- 中介者模式
- 原型模式
- 命令模式
- 外觀模式
- 工廠模式
- Mixin 模式
- 裝飾模式
- 亨元(Flyweight)模式
- JavaScript MV* 模式
- MVC 模式
- MVP 模式
- MVVM 模式
- 最新的模塊化 JavaScript 設計模式
- AMD
- CommonJS
- ES Harmony
- JQuery 中的設計模式
- 組合模式
- 適配器模式
- 外觀模式
- 觀察者模式
- 迭代器模式
- 惰性初始模式
- 代理模式
- 建造者模式
- jQuery 插件的設計模式
- JavaScript 命名空間模式
- 總結
- 參考