工廠模式
工廠模式是另外一種關(guān)注對(duì)象創(chuàng)建概念的創(chuàng)建模式嘿般。它的領(lǐng)域中同其它模式的不同之處在于它并沒(méi)有明確要求我們使用一個(gè)構(gòu)造器。取而代之涯冠,一個(gè)工廠能提供一個(gè)創(chuàng)建對(duì)象的公共接口炉奴,我們可以在其中指定我們希望被創(chuàng)建的工廠對(duì)象的類(lèi)型。
試想一下蛇更,在我們被要求創(chuàng)建一種類(lèi)型的UI組件時(shí)瞻赶,我們就有一個(gè)UI工廠。并不是通過(guò)直接使用new操作符或者通過(guò)另外一個(gè)構(gòu)造器來(lái)創(chuàng)建這個(gè)組件派任,我們?nèi)《南蛞粋€(gè)工廠對(duì)象索要一個(gè)新的組件砸逊。我們告知工廠我們需要什么類(lèi)型的組件(例如:“按鈕”,“面板”)掌逛,而它會(huì)將其初始化师逸,然后返回供我們使用。
如果創(chuàng)建過(guò)程相當(dāng)復(fù)雜的話豆混,那這會(huì)特別的有用篓像,例如:如果它強(qiáng)烈依賴于動(dòng)態(tài)因素或者應(yīng)用程序配置的話。
這個(gè)模式的一些例子可以在UI庫(kù)里面找到崖叫,例如ExtJS, 用于創(chuàng)建對(duì)象或者組件的方法可以被做更深層次的子類(lèi)遗淳。 下面使用用我們之前的那些代碼來(lái)做的一個(gè)例子,通過(guò)使用構(gòu)造器模式邏輯來(lái)定義汽車(chē)心傀。這個(gè)例子展示了Vehicle 工廠可以使用工廠模式來(lái)實(shí)現(xiàn)。
// 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 實(shí)例使用 Truck 類(lèi)
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 的子類(lèi)用于創(chuàng)建一個(gè)工廠類(lèi)生產(chǎn) 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 );
何時(shí)使用工廠模式
當(dāng)被應(yīng)用到下面的場(chǎng)景中時(shí)拆讯,工廠模式特別有用:
當(dāng)我們的對(duì)象或者組件設(shè)置涉及到高程度級(jí)別的復(fù)雜度時(shí)脂男。
當(dāng)我們需要根據(jù)我們所在的環(huán)境方便的生成不同對(duì)象的實(shí)體時(shí)养叛。
當(dāng)我們?cè)谠S多共享同一個(gè)屬性的許多小型對(duì)象或組件上工作時(shí)。
當(dāng)帶有其它僅僅需要滿足一種API約定(又名鴨式類(lèi)型)的對(duì)象的組合對(duì)象工作時(shí).這對(duì)于解耦來(lái)說(shuō)是有用的宰翅。
何時(shí)不要去使用工廠模式
當(dāng)被應(yīng)用到錯(cuò)誤的問(wèn)題類(lèi)型上時(shí),這一模式會(huì)給應(yīng)用程序引入大量不必要的復(fù)雜性.除非為創(chuàng)建對(duì)象提供一個(gè)接口是我們編寫(xiě)的庫(kù)或者框架的一個(gè)設(shè)計(jì)上目標(biāo),否則我會(huì)建議使用明確的構(gòu)造器,以避免不必要的開(kāi)銷(xiāo)弃甥。
由于對(duì)象的創(chuàng)建過(guò)程被高效的抽象在一個(gè)接口后面的事實(shí),這也會(huì)給依賴于這個(gè)過(guò)程可能會(huì)有多復(fù)雜的單元測(cè)試帶來(lái)問(wèn)題。
抽象工廠
了解抽象工廠模式也是非常實(shí)用的,它的目標(biāo)是以一個(gè)通用的目標(biāo)將一組獨(dú)立的工廠進(jìn)行封裝.它將一堆對(duì)象的實(shí)現(xiàn)細(xì)節(jié)從它們的一般用例中分離汁讼。
抽象工廠應(yīng)該被用在一種必須從其創(chuàng)建或生成對(duì)象的方式處獨(dú)立,或者需要同多種類(lèi)型的對(duì)象一起工作,這樣的系統(tǒng)中淆攻。
簡(jiǎn)單且容易理解的例子就是一個(gè)發(fā)動(dòng)機(jī)工廠,它定義了獲取或者注冊(cè)發(fā)動(dòng)機(jī)類(lèi)型的方式.抽象工廠會(huì)被命名為AbstractVehicleFactory.抽象工廠將允許像"car"或者"truck"的發(fā)動(dòng)機(jī)類(lèi)型的定義,并且構(gòu)造工廠將僅實(shí)現(xiàn)滿足發(fā)動(dòng)機(jī)合同的類(lèi).(例如: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" } );