Javascript中Factory的应用

这里拿Pro Javascript Design Pattern中的例子作为case。假如一家自行车店销售各种自行车:

/* The Bicycle interface. */

var Bicycle = new Interface("Bicycle", ["assemble", "wash", "ride", "repair"]);

/* Speedster class. */

var Speedster = function () { }

Speedster.prototype = {

assemble: function () {

console.log("Speedster Bicycle assembled.");

},

wash: function () {

console.log("Speedster Bicycle washed.");

},

ride: function () {

console.log("Speedster Bicycle ride.");

},

repair: function () {

console.log("Speedster Bicycle repaired.");

}

};

Speedster.prototype.constructor = Speedster;

/* Lowrider class. */

var Lowrider = function () { }

Lowrider.prototype = {

assemble: function () {

console.log("Lowrider Bicycle assembled.");

},

wash: function () {

console.log("Lowrider Bicycle washed.");

},

ride: function () {

console.log("Lowrider Bicycle ride.");

},

repair: function () {

console.log("Lowrider Bicycle repaired.");

}

};

Lowrider.prototype.constructor = Lowrider;

/* ComfortCruiser class. */

var ComfortCruiser = function () { }

ComfortCruiser.prototype = {

assemble: function () {

console.log("ComfortCruiser Bicycle assembled.");

},

wash: function () {

console.log("ComfortCruiser Bicycle washed.");

},

ride: function () {

console.log("ComfortCruiser Bicycle ride.");

},

repair: function () {

console.log("ComfortCruiser Bicycle repaired.");

}

};

ComfortCruiser.prototype.constructor = ComfortCruiser;

/* BicycleShop class. */

var BicycleShop = function () { };

BicycleShop.prototype = {

sellBicycle: function (model) {

var bicycle;

switch (model) {

case "The Speedster":

bicycle = new Speedster();

break;

case "The Lowrider":

bicycle = new Lowrider();

break;

case "The Comfort Cruiser":

default:

bicycle = new ComfortCruiser();

break;

}

Interface.ensureImplements(bicycle, [Bicycle]);

bicycle.assemble();

bicycle.wash();

return bicycle;

}

};

BicycleShop.prototype.constructor = BicycleShop;

/* test */

(function () {

var bicycle = new BicycleShop().sellBicycle("The Lowrider");

bicycle.ride();

bicycle.repair();

})();

其中,

Bicycle为自行车接口,之后3个类为类型的自行车,在BicycleShop的SellBicycle中是先根据条件创建具体自行车型,然后组装清洗。

改进第一步是将上述SellBicycle方法利用Simple Factory进行改进:

/* Bicycle Factory */

var BicycleFactory = {

createBicycle: function (model) {

var bicycle;

switch (model) {

case "The Speedster":

bicycle = new Speedster();

break;

case "The Lowrider":

bicycle = new Lowrider();

break;

case "The Comfort Cruiser":

default:

bicycle = new ComfortCruiser();

break;

}

Interface.ensureImplements(bicycle, [Bicycle]);

return bicycle;

}

};

/* BicycleShop class. */

var BicycleShop = function () { };

BicycleShop.prototype = {

sellBicycle: function (model) {

var bicycle = BicycleFactory.createBicycle(model);

bicycle.assemble();

bicycle.wash();

return bicycle;

}

};

BicycleShop.prototype.constructor = BicycleShop;

可以看到,多了一个Bicycle构造工厂, BicycleShop的职责只负责组装和清洗了。 当增加了新的车型,只需要更新BicycleFactory,不需要修改BicycleShop。

好,当车型比较少时完全可以满足需要。但是,当车店需要区分品牌和车型时就不行了。我们继续,利用Factory Method来进行改进。因为改动较大,贴出完整代码如下:

/* The Bicycle interface. */

var Bicycle = new Interface("Bicycle", ["assemble", "wash", "ride", "repair"]);

/* Acme Speedster class. */

var AcmeSpeedster = function () { }

AcmeSpeedster.prototype = {

assemble: function () {

console.log("Acme Speedster Bicycle assembled.");

},

wash: function () {

console.log("Acme Speedster Bicycle washed.");

},

ride: function () {

console.log("Acme Speedster Bicycle ride.");

},

repair: function () {

console.log("Acme Speedster Bicycle repaired.");

}

};

AcmeSpeedster.prototype.constructor = AcmeSpeedster;

/* Acme Lowrider class. */

var AcmeLowrider = function () { }

AcmeLowrider.prototype = {

assemble: function () {

console.log("Acme Lowrider Bicycle assembled.");

},

wash: function () {

console.log("Acme Lowrider Bicycle washed.");

},

ride: function () {

console.log("Acme Lowrider Bicycle ride.");

},

repair: function () {

console.log("Acme Lowrider Bicycle repaired.");

}

};

AcmeLowrider.prototype.constructor = AcmeLowrider;

/* Acme ComfortCruiser class. */

var AcmeComfortCruiser = function () { }

AcmeComfortCruiser.prototype = {

assemble: function () {

console.log("Acme ComfortCruiser Bicycle assembled.");

},

wash: function () {

console.log("Acme ComfortCruiser Bicycle washed.");

},

ride: function () {

console.log("Acme ComfortCruiser Bicycle ride.");

},

repair: function () {

console.log("Acme ComfortCruiser Bicycle repaired.");

}

};

AcmeComfortCruiser.prototype.constructor = AcmeComfortCruiser;

/* General Speedster class. */

var GeneralSpeedster = function () { }

GeneralSpeedster.prototype = {

assemble: function () {

console.log("General Speedster Bicycle assembled.");

},

wash: function () {

console.log("General Speedster Bicycle washed.");

},

ride: function () {

console.log("General Speedster Bicycle ride.");

},

repair: function () {

console.log("General Speedster Bicycle repaired.");

}

};

GeneralSpeedster.prototype.constructor = GeneralSpeedster;

/* General Lowrider class. */

var GeneralLowrider = function () { }

GeneralLowrider.prototype = {

assemble: function () {

console.log("General Lowrider Bicycle assembled.");

},

wash: function () {

console.log("General Lowrider Bicycle washed.");

},

ride: function () {

console.log("General Lowrider Bicycle ride.");

},

repair: function () {

console.log("General Lowrider Bicycle repaired.");

}

};

GeneralLowrider.prototype.constructor = GeneralLowrider;

/* General ComfortCruiser class. */

var GeneralComfortCruiser = function () { }

GeneralComfortCruiser.prototype = {

assemble: function () {

console.log("General ComfortCruiser Bicycle assembled.");

},

wash: function () {

console.log("General ComfortCruiser Bicycle washed.");

},

ride: function () {

console.log("General ComfortCruiser Bicycle ride.");

},

repair: function () {

console.log("General ComfortCruiser Bicycle repaired.");

}

};

GeneralComfortCruiser.prototype.constructor = GeneralComfortCruiser;

/* BicycleShop class. */

var BicycleShop = function () { };

BicycleShop.prototype = {

sellBicycle: function (model) {

var bicycle = this.createBicycle(model);

bicycle.assemble();

bicycle.wash();

return bicycle;

},

createBicycle: function (model) {

throw new Error("BicycleShop is abstract, not implements createBicycle.");

}

};

BicycleShop.prototype.constructor = BicycleShop;

/* Acme Bicycle Shop */

var AcmeBicycleShop = function () { };

extend(AcmeBicycleShop, BicycleShop);

AcmeBicycleShop.prototype.createBicycle = function (model) {

var bicycle;

switch (model) {

case "The Speedster":

bicycle = new AcmeSpeedster();

break;

case "The Lowrider":

bicycle = new AcmeLowrider();

break;

case "The Comfort Cruiser":

default:

bicycle = new AcmeComfortCruiser();

break;

}

Interface.ensureImplements(bicycle, [Bicycle]);

return bicycle;

};

/* General Bicycle Shop */

var GeneralBicycleShop = function () { };

extend(GeneralBicycleShop, BicycleShop);

GeneralBicycleShop.prototype.createBicycle = function (model) {

var bicycle;

switch (model) {

case "The Speedster":

bicycle = new GeneralSpeedster();

break;

case "The Lowrider":

bicycle = new GeneralLowrider();

break;

case "The Comfort Cruiser":

default:

bicycle = new GeneralComfortCruiser();

break;

}

Interface.ensureImplements(bicycle, [Bicycle]);

return bicycle;

};

/* test */

(function () {

var bicycle = new GeneralBicycleShop().sellBicycle("The Lowrider");

bicycle.ride();

bicycle.repair();

})();

重点在于,我们将

BicycleShop变更为一个抽象类,即将CreateBicycle()方法作为抽象方法。然后, AcmeBicycleShop 和 GeneralBicycleShop作为2个品牌的自行车店均继承于它,各自实现CreateBicycle()方法。

另外,附件还附有2个例子,download