JS设计模式7 - 工厂与抽象工厂
2017-03-23 本文已影响157人
转角遇见一直熊
工厂模式
工厂模式目的
设计一个创建对象的方法,让派生类控制对象创建的过程。
何时使用
- 不知道要创建的具体类
- 派生类指定具体的创建过程和细节
- 父类希望延迟创建到派生类
举例
很多系统都有用户和用户组的概念,比如linux系统,当系统想创建一个用户的时候,系统会把创建的工作交给各个具体的用户实现类。父类会处理所有的公共操作,派生类则会定一个工厂方法来处理特殊的操作。系统可能又AdminUser和StandardUser,但是他们都派生于UserObject。AdminUser在创建的时候可能会做一些额外的操作确保自己的权限比较大。
代码
/**
* @author: Mark Gable
* @fileOverview: An example of the Factory design pattern
*/
// http://codepen.io/mgable43/pen/rsjGC
/** @namespace */
var myPizzaFactory = (function () {
"use strict";
/**
* simplePizzaFactory constructs a simplePizzaFactory object
* @param {string} type pizza type
* @method createPizza
* @returns {object} pizza object
*/
var simplePizzaFactory = function () {
return {
createPizza : function (type) {
var pizza = "unknown";
if (type === "cheese") {
pizza = cheesePizza();
}else if (type === "pepperoni") {
pizza = pepperoniPizza();
}
return pizza;
}
}
},
/**
* pizzaStore constructs a pizzaStore object
* @param {object} factory simplePizzaFactory object
* @method orderPizza
* @returns {object} pizza object
* @note This is an example of a Factory design pattern
*/
pizzaStore = function (factory) {
return {
orderPizza : function (type) {
var pizza = factory.createPizza (type);
console.info ( pizza.prepare() );
console.info ( pizza.bake() );
console.info ( pizza.cut() );
console.info ( pizza.box() );
return pizza;
}
}
},
/**
* pizza constructs a pizza object
* @param {object} specs specifies pizza characteristics
* @returns {object} pizza object
*/
pizza = function (specs){
return {
name: specs.name || "unknown",
dough: specs.dough || "unknown",
sauce: specs.sauce || "unknown",
prepare: specs.prepare || function () { return "Preparing " + this.name },
bake: specs.bake || function () { return "Bake for 25 minutes at 350" },
cut: specs.cut || function () { return "Cutting pizza into diagonal slices" },
box: specs.box || function () { return "Place pizza in box" },
}
},
/**
* cheesePizza constructs a cheesePizza object
* @returns {object} cheese pizza object
*/
cheesePizza = function () {
return pizza ({
name: "cheese pizza",
dough: "thin crust",
sauce: "Marinara sauce",
cut: function () { return "Cutting the pizza into squares" }
});
},
/**
* pepperoniPizza constructs a pepperoniPizza object
* @returns {object} pepperoni pizza object
*/
pepperoniPizza = function () {
return pizza ({
name: "pepperoni pizza",
dough: "thick crust",
sauce: "Plum sauce",
bake: function () { return "Bake for 30 minutes at 325" }
});
};
var store = pizzaStore(simplePizzaFactory());
store.orderPizza ("cheese");
store.orderPizza ("pepperoni");
})();
上面的代码实现了工厂模式的思想,simplePizzaFactory可以用来创建不同的Pizza,它并不知道如何创建,而是把具体的操作交给cheesePizza和pepperoniPizza。
当使用JavaScript语言来实现设计模式的时候,往往不需要拘泥于静态语言的继承方式,相反,我们应该关注思想本身。
抽象工厂
抽象工厂目的
提供接口创建系列产品
何时使用
- 创建的对象和使用它们的系统是分离的
- 需要创建的对象是家族式的
- 创建的众多对象是在一起使用的
- 具体创建对象的类和系统解耦
举例
在游戏中往往需要创建大量对象,下面的代码需要创建巫师和剑士,他们自己分别又包含很多对象。
代码
const factoryType = {
swordsman: "swordsman",
wizard: "wizard"
};
class IHeroFactory {
createAbilities() {
}
createEquipment() {
}
createSkills() {
}
}
class SwordsmanFactory extends IHeroFactory {
createAbilities() {
return new SwordsmanAbility();
}
createEquipment() {
return new SwordsmanEquipment();
}
createSkills() {
return new SwordsmanSkill();
}
}
class WizardFactory extends IHeroFactory {
createAbilities() {
return new WizardAbilitiy();
}
createEquipment() {
return new WizardEquipment();
}
createSkills() {
return new WizardSkill();
}
}
class FactoryMaker {
static getHeroFactory(type) {
var factory = null;
switch(type) {
case factoryType.wizard:
factory = new WizardFactory();
break;
case factoryType.swordsman:
factory = new SwordsmanFactory();
break;
}
return factory;
}
}
class IAbstractSkill {
getMainSkill() {
}
getSecondarySkill() {
}
}
class SwordsmanSkill extends IAbstractSkill {
constructor() {
super();
this._mainSkillName = "slash";
this._secondarySkillType = "berserk";
}
getMainSkill() {
return this._mainSkillName;
}
getSecondarySkill() {
return this._secondarySkillType;
}
}
class WizardSkill extends IAbstractSkill {
constructor() {
super();
this._mainSkillName = "fireball";
this._secondarySkillType = "tornado";
}
getMainSkill() {
return this._mainSkillName;
}
getSecondarySkill() {
return this._secondarySkillType;
}
}
class IAbstractEquipment {
getEquipment() {
}
}
class SwordsmanEquipment extends IAbstractEquipment {
constructor() {
super();
this._equipment = {
type: "Robe of the Chaos",
armor: 20,
resistance: 100
}
}
getEquipment() {
return this._equipment;
}
}
class WizardEquipment extends IAbstractEquipment {
constructor() {
super();
this._equipment = {
type: "Wrath of the Lich King",
armor: 3,
extraIntelligence: 5,
extraMP: 100
}
}
getEquipment() {
return this._equipment;
}
}
class IAbstractAbility {
getAbilities() {
}
}
class SwordsmanAbility extends IAbstractAbility {
constructor() {
super();
this._heroProperties = {
strength: 10,
agility: 5,
extraPower: true,
extraPowerLevel: 1
}
}
getAbilities() {
return this._heroProperties;
}
}
class WizardAbilitiy extends IAbstractAbility {
constructor() {
super();
this._heroProperties = {
strength: 10,
intelligence: 30,
agility: 5
};
}
getAbilities() {
return this._heroProperties;
}
}
(function run () {
let wizardFactory = FactoryMaker.getHeroFactory(factoryType.wizard),
swordsmanFactory = FactoryMaker.getHeroFactory(factoryType.swordsman);
let wiz = {
abilities: wizardFactory.createAbilities(),
equipment: wizardFactory.createEquipment(),
skills: wizardFactory.createSkills()
};
let swrd = {
abilities: swordsmanFactory.createAbilities(),
equipment: swordsmanFactory.createEquipment(),
skills: swordsmanFactory.createSkills()
};
let testHero = {
abilities: wizardFactory.createAbilities(),
equipment: wizardFactory.createEquipment(),
skills: swordsmanFactory.createSkills()
};
console.log(wiz, swrd, testHero);
})();
上面的代码有两个工厂,一个是男巫(wizard),一个是剑客。创建这两个对象的时候还需要给他们赋予能力,装备和技能。这些对象都是相关的。这里的代码模拟了Java,提供了IHeroFactory接口,可以看到这个接口可以创建三个对象。
结论
工厂方法让我们摆脱new操作符,这样我们就不需要依赖于具体的实现类。抽象工厂让我们可以创建相关的一系列产品。抽象工厂包装了独立的工厂,但是这些工厂创建的产品是在一起使用的。
https://github.com/benhaben/essentialjsdesignpatterns.git