1. 工厂模式的特点
在我们现实生活中,买馒头和自己蒸馒头、去饭店点一份大盘鸡和自己养鸡,杀鸡,做大盘鸡,这是全然不同的两种体验:
自己做麻烦,而且有失败的风险,需要自己承担后果。
买现成的,可以忽略制作细节,方便快捷并且无风险,得到的肯定是美味的食物。
对于后者,就相当于是一个加工厂,通过这个工厂我们就可以得到想要的东西,在程序设计中,这种模式就叫做工厂模式,工厂生成出的产品就是某个类的实例,也就是对象。关于工厂模式一共有三种,分别是:简单工厂模式、工厂模式、抽象工厂模式。
先介绍简单工厂模式。
基于简单工厂模式去创建对象的时候,需要提供一个工厂类,专门用于生产需要的对象,这样关于对象的创建操作就被剥离出去了。
简单工厂模式相关类的创建和使用步骤如下:
创建一个新的类, 可以将这个类称之为工厂类。对于简单工厂模式来说,需要的工厂类只有一个。
在这个工厂类中添加一个公共的成员函数,通过这个函数来创建我们需要的对象,关于这个函数一般将其称之为工厂函数。
关于使用,首先创建一个工厂类对象,然后通过这个对象调用工厂函数,这样就可以生产出一个指定类型的实例对象了。
2. 生产的产品
在海贼世界中,凯撒·库朗研制的人造恶魔果实是有瑕疵的,吃下人造恶魔果实的失败品没能成功获得果实能力的人,会被剥夺除笑以外的一切表情,所以人造恶魔果实被称为SMILE。
下面是明哥的SMILE工厂要生产的众多人造动物系恶魔果实中的三种:
// 人造恶魔果实· 绵羊形态
class SheepSmile
{
public:
void transform()
{
cout << "变成人兽 -- 山羊人形态..." << endl;
}
void ability()
{
cout << "将手臂变成绵羊角的招式 -- 巨羊角" << endl;
}
};
// 人造恶魔果实· 狮子形态
class LionSmile
{
public:
void transform()
{
cout << "变成人兽 -- 狮子人形态..." << endl;
}
void ability()
{
cout << "火遁· 豪火球之术..." << endl;
}
};
// 人造恶魔果实· 蝙蝠形态
class BatSmile
{
public:
void transform()
{
cout << "变成人兽 -- 蝙蝠人形态..." << endl;
}
void ability()
{
cout << "声纳引箭之万剑归宗..." << endl;
}
};
不论是吃了那种恶魔果实,获得了相应的能力之后,可以做的事情大体是相同的,那就是形态变化transform() 和 使用果实能力alility()。
另外,生产这些恶魔果实的时候可能需要极其复杂的参数,在此就省略了【也就是说这些类的构造函数的参数在此被省略了】。
3. 如何生产
如果想要生产出这些恶魔果实,可以先创建一个工厂类,然后再给这个工厂类添加一个工厂函数,又因为我们要生成三种不同类型的恶魔果实,所以可以给工厂函数添加一个参数,用以控制当前要生产的是哪一类。
enum class Type:char{SHEEP, LION, BAT};
// 恶魔果实工厂类
class SmileFactory
{
public:
enum class Type:char{SHEEP, LION, BAT};
SmileFactory() {}
~SmileFactory() {}
void* createSmile(Type type)
{
void* ptr = nullptr;
switch (type)
{
case Type::SHEEP:
ptr = new SheepSmile;
break;
case Type::LION:
ptr = new LionSmile;
break;
case Type::BAT:
ptr = new BatSmile;
break;
default:
break;
}
return ptr;
}
};
int main()
{
SmileFactory* factory = new SmileFactory;
BatSmile* batObj = (BatSmile*)factory->createSmile(Type::BAT);
return 0;
}
关于恶魔果实的类型,上面的类中用到了强类型枚举(C++11新特性),增强了代码的可读性,并且将枚举元素设置为了char类型,节省了内存。
函数createSmile(Type type)的返回值是void*类型,这样处理主要是因为每个case 语句创建出的对象类型是不一样的,为了实现兼容,故此这样处理。
得到函数createSmile(Type type)的返回值之后,还需要将其转换成实际的类型,处理起来还是比较繁琐的。
简单工厂模式的弊端
在上一节简单工厂模式中,创建了一个工厂类,用于生产需要的对象,但是这种方式有一个弊端,它违反了设计模式中的开放-封闭原则,在上面的工厂函数中需要生成三种人造恶魔果实,现在如果想要生成更多,那么就需要在工厂函数的switch语句中添加更多的case,很明显这违背了封闭原则,也就意味着需要基于开放原则来解决这个问题。
使用工厂模式可以很完美的解决上述的问题,简单工厂模式是只有一个工厂类,而工厂模式是有很多的工厂类:
一个基类,包含一个虚工厂函数,用于实现多态。
多个子类,重写父类的工厂函数。每个子工厂类负责生产一种恶魔果实,这相当于再次解耦,将工厂类的职责再次拆分、细化,如果要生产新品种的恶魔果实,那么只需要添加对应的工厂类,无需修改原有的代码。
2. 工厂模式
我们先修改一下简单工厂模式中工厂类相关的代码:
// 恶魔果实工厂类
class AbstractFactory
{
public:
virtual AbstractSmile* createSmile() = 0;
virtual ~AbstractFactory() {}
};
class SheepFactory : public AbstractFactory
{
public:
AbstractSmile* createSmile() override
{
return new SheepSmile;
}
~SheepFactory()
{
cout << "释放 SheepFactory 类相关的内存资源" << endl;
}
};
class LionFactory : public AbstractFactory
{
public:
AbstractSmile* createSmile() override
{
return new LionSmile;
}
~LionFactory()
{
cout << "释放 LionFactory 类相关的内存资源" << endl;
}
};
class BatFactory : public AbstractFactory
{
public:
AbstractSmile* createSmile() override
{
return new BatSmile;
}
~BatFactory()
{
cout << "释放 BatFactory 类相关的内存资源" << endl;
}
};
通过示例代码可以看到,每个工厂类其实都不复杂,在每个子工厂类中也只是重写了父类的工厂方法而已,每个子工厂类生产一种恶魔果实,但是工厂函数的返回值确是恶魔果实类的基类类型,相当于是使用父类指针指向了子类对象,此处也是用到了多态。通过这样的处理,工厂函数也就不再需要参数了。
完整的代码应该是这样的:
#include <iostream>
using namespace std;
class AbstractSmile
{
public:
virtual void transform() = 0;
virtual void ability() = 0;
virtual ~AbstractSmile() {}
};
// 人造恶魔果实· 绵羊形态
class SheepSmile : public AbstractSmile
{
public:
void transform() override
{
cout << "变成人兽 -- 山羊人形态..." << endl;
}
void ability() override
{
cout << "将手臂变成绵羊角的招式 -- 巨羊角" << endl;
}
};
// 人造恶魔果实· 狮子形态
class LionSmile : public AbstractSmile
{
public:
void transform() override
{
cout << "变成人兽 -- 狮子人形态..." << endl;
}
void ability() override
{
cout << "火遁· 豪火球之术..." << endl;
}
};
class BatSmile : public AbstractSmile
{
public:
void transform() override
{
cout << "变成人兽 -- 蝙蝠人形态..." << endl;
}
void ability() override
{
cout << "声纳引箭之万剑归宗..." << endl;
}
};
// 恶魔果实工厂类
class AbstractFactory
{
public:
virtual AbstractSmile* createSmile() = 0;
virtual ~AbstractFactory() {}
};
class SheepFactory : public AbstractFactory
{
public:
AbstractSmile* createSmile() override
{
return new SheepSmile;
}
~SheepFactory()
{
cout << "释放 SheepFactory 类相关的内存资源" << endl;
}
};
class LionFactory : public AbstractFactory
{
public:
// 工厂函数
AbstractSmile* createSmile() override
{
return new LionSmile;
}
~LionFactory()
{
cout << "释放 LionFactory 类相关的内存资源" << endl;
}
};
class BatFactory : public AbstractFactory
{
public:
// 工厂函数
AbstractSmile* createSmile() override
{
return new BatSmile;
}
~BatFactory()
{
cout << "释放 BatFactory 类相关的内存资源" << endl;
}
};
int main()
{
AbstractFactory* factory = new BatFactory;
AbstractSmile* obj = factory->createSmile();
obj->transform();
obj->ability();
return 0;
}
。
抽象工厂:
抽象工厂模式适用于比较复杂的多变的业务场景,总体上就是给一系列功能相同但是属性会发生变化的组件(如:船体材料、武器系统、动力系统)添加一个抽象类,这样就可以非常方便地进行后续的拓展,再搭配工厂类就可以创建出我们需要的对象了。
#include <iostream>
#include <string>
using namespace std;
// 船体
class ShipBody
{
public:
virtual string getShipBody() = 0;
virtual ~ShipBody() {}
};
class WoodBody : public ShipBody
{
public:
string getShipBody() override
{
return string("用<木材>制作轮船船体...");
}
};
class IronBody : public ShipBody
{
public:
string getShipBody() override
{
return string("用<钢铁>制作轮船船体...");
}
};
class MetalBody : public ShipBody
{
public:
string getShipBody() override
{
return string("用<合金>制作轮船船体...");
}
};
// 武器
class Weapon
{
public:
virtual string getWeapon() = 0;
virtual ~Weapon() {}
};
class Gun : public Weapon
{
public:
string getWeapon() override
{
return string("配备的武器是<枪>...");
}
};
class Cannon : public Weapon
{
public:
string getWeapon() override
{
return string("配备的武器是<自动机关炮>...");
}
};
class Laser : public Weapon
{
public:
string getWeapon() override
{
return string("配备的武器是<激光>...");
}
};
// 动力
class Engine
{
public:
virtual string getEngine() = 0;
virtual ~Engine() {}
};
class Human : public Engine
{
public:
string getEngine() override
{
return string("使用<人力驱动>...");
}
};
class Diesel : public Engine
{
public:
string getEngine() override
{
return string("使用<内燃机驱动>...");
}
};
class Nuclear : public Engine
{
public:
string getEngine() override
{
return string("使用<核能驱动>...");
}
};
// 轮船类
class Ship
{
public:
Ship(ShipBody* body, Weapon* weapon, Engine* engine) :
m_body(body), m_weapon(weapon), m_engine(engine)
{
}
string getProperty()
{
string info = m_body->getShipBody() + m_weapon->getWeapon() + m_engine->getEngine();
return info;
}
~Ship()
{
delete m_body;
delete m_engine;
delete m_weapon;
}
private:
ShipBody* m_body = nullptr;
Weapon* m_weapon = nullptr;
Engine* m_engine = nullptr;
};
// 工厂类
class AbstractFactory
{
public:
virtual Ship* createShip() = 0;
virtual ~AbstractFactory() {}
};
class BasicFactory : public AbstractFactory
{
public:
Ship* createShip() override
{
Ship* ship = new Ship(new WoodBody, new Gun, new Human);
cout << "<基础型>战船生产完毕, 可以下水啦..." << endl;
return ship;
}
};
class StandardFactory : public AbstractFactory
{
public:
Ship* createShip() override
{
Ship* ship = new Ship(new IronBody, new Cannon, new Diesel);
cout << "<标准型>战船生产完毕, 可以下水啦..." << endl;
return ship;
}
};
class UltimateFactory : public AbstractFactory
{
public:
Ship* createShip() override
{
Ship* ship = new Ship(new MetalBody, new Laser, new Nuclear);
cout << "<旗舰型>战船生产完毕, 可以下水啦..." << endl;
return ship;
}
};
int main()
{
AbstractFactory* factroy = new StandardFactory;
Ship* ship = factroy->createShip();
cout << ship->getProperty();
delete ship;
delete factroy;
return 0;
}
总结:
- 简单工厂模式不能遵守开放-封闭原则,工厂和抽象工厂模式可以
- 简单工厂模式只有一个工厂类,工厂和抽象工厂有多个工厂类
- 工厂模式创建的产品对象相对简单,抽象工厂模式创建的产品对象相对复杂
- 工厂模式创建的对象对应的类不需要提供抽象类【这产品类组件中没有可变因素】
- 抽象工厂模式创建的对象对应的类有抽象的基类【这个产品类组件中有可变因素