这里拿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();
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;
}
};
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();
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