抽象工厂(Abstruct Factory)模式
抽象工厂(Abstruct Factory)模式
之前一直强调,工厂模式只能为一类类提供对象的创建。而抽象工厂模式与之最大区别,便是它能为多个有依赖关系的类实现对象的创建。
我更倾向于认为,当在工厂模式中有多个不相同的基类,但其特征在实例化的类上产生了交叉。我们将这些不同的特征在产品类族与工厂类族中用相反的继承关系表达出来,完成对一类相关类的创建。
举个例子: 在一款游戏中,用户使用的道具(Prop)分为武器(Weapon)和玩具(Toy),枪械(Gun)有手枪(Handgun)和猎枪(Shotgun)。道具实体有武器手枪(WeaponHandgun),武器猎枪(WeaponShotgun),玩具手枪(ToyHandgun),玩具猎枪(ToyShotgun).很明显,道具特征和枪械特征在其共同的派生类中完成了整合。(由于某些语言不支持多重继承,也就不使用多重继承)也就是这两个类具有相关性。
如图: FactoryGun提供的是两类(Weapon,Toy)对象的创建,而具体创建那种实例,需要其派生类来决定。我们发现,在产品类族中,道具,与枪械类型的继承关系与工厂类族正好相反,产品类族中,枪械类型是从道具中分化出来,而在工厂类族中,我们枪械类型决定具体的产品。也就是说,在产品类族中,我们首先确定是哪种道具,然后在确定是哪种枪械;在工厂类族中,我们在知道枪械类型后,通过调用函数的不同,才确定是那种道具。这样,当我们需要增加枪械类型时,直接更改工厂的派生类型;当增加了道具类型时,更改基类类型。
***注意:***,此UML图中体现上面所说的特征逆置不太直观,可以尝试着去掉FactoryGun,按照工厂方法写出来,就会比较直观的看到多个类,及依赖关系在产品类族中与在工厂类族中的不同。
其实,这种逆置是符合依赖倒置原则的。
#include <iostream>
#ifndef _DESIGN_PATTERN_ABSTRACT_FACTORY_WEAPON_HPP_
#define _DESIGN_PATTERN_ABSTRACT_FACTORY_WEAPON_HPP_
namespace design_pattern
{
class Weapon
{
public:
virtual ~Weapon() {}
virtual void Shoot() = 0;
};
class WeaponHandgun : public Weapon
{
public:
void Shoot()
{
std::cout << "WeaponHandgun shoot: 10.0" << std::endl;
}
};
class WeaponShotgun : public Weapon
{
public:
void Shoot()
{
std::cout << "WeaponShotgun shoot: kill a goat" << std::endl;
}
};
}
#endif //!_DESIGN_PATTERN_ABSTRACT_FACTORY_WEAPON_HPP_
#include <iostream>
#ifndef _DESIGN_PATTERN_ABSTRACT_FACTORY_TOY_HPP_
#define _DESIGN_PATTERN_ABSTRACT_FACTORY_TOY_HPP_
namespace design_pattern
{
class Toy
{
public:
virtual ~Toy() {}
virtual void Shoot() = 0;
};
class ToyHandgun : public Toy
{
public:
void Shoot()
{
std::cout << "ToyHandgun shoot: bi bi bu..." << std::endl;
}
};
class ToyShotgun : public Toy
{
void Shoot()
{
std::cout << "ToyShotgun shoot: so so so..." << std::endl;
}
};
}
#endif // !_DESIGN_PATTERN_ABSTRACT_FACTORY_TOY_HPP_
//factory_gun.hpp
#include "weapon.hpp"
#include "toy.hpp"
#ifndef _DESIGN_PATTERN_ABSTRACT_FACTORY_FACTORY_GUN_HPP_
#define _DESIGN_PATTERN_ABSTRACT_FACTORY_FACTORY_GUN_HPP_
namespace design_pattern
{
class FactoryGun
{
public:
virtual ~FactoryGun() {}
virtual Weapon* CreateWeapon() = 0;
virtual Toy* CreateToy() = 0;
};
class FactoryHandgun : public FactoryGun
{
public:
Weapon* CreateWeapon()
{
return new WeaponHandgun;
}
Toy* CreateToy()
{
return new ToyHandgun;
}
};
class FactoryShotgun : public FactoryGun
{
Weapon* CreateWeapon()
{
return new WeaponShotgun;
}
Toy* CreateToy()
{
return new ToyShotgun;
}
};
}
#endif // !_DESIGN_PATTERN_ABSTRACT_FACTORY_FACTORY_GUN_HPP_
//abstract_factory_main.cpp
#include "weapon.hpp"
#include "toy.hpp"
#include "factory_gun.hpp"
using namespace design_pattern;
int main()
{
FactoryGun *phand = new FactoryHandgun;
FactoryGun *pshot = new FactoryShotgun;
Weapon *pwhg = phand->CreateWeapon();
Toy *pthg = phand->CreateToy();
Weapon *pwsg = pshot->CreateWeapon();
Toy *ptsg = pshot->CreateToy();
pwhg->Shoot();
pwsg->Shoot();
pthg->Shoot();
ptsg->Shoot();
return 0;
}
语法tips
- C++继承之内存布局