C++工厂方法之对象创建型模式详解
1.代码示例
工厂方法模式,简称工厂模式或者多态工厂模式。与简单工厂模式相比,引入了更多的新类,灵活性更强,实现也更加复杂。符合开闭原则,付出的代价是需要新增加多个新的工厂类。
如下,M_UndeadFactory
、M_ElementFactory
、M_MechanicFactory
类有一个共同的父类 M_ParFactory(工厂抽象类)。
M_ParFactory 类中的 createMonster 成员函数其实就是个工厂方法,工厂方法模式的名字也是由此而来。
#include <iostream> using namespace std; // 怪物父类 class Monster { public: // 构造函数 Monster(int life, int magic, int attack) : m_life(life), m_magic(magic), m_attack(attack) {} virtual ~Monster() {} // 父类的析构函数应该为虚函数 protected: // 可能被子类访问的成员,所以用protected修饰 int m_life; // 生命值 int m_magic; // 魔法值 int m_attack; // 攻击力 }; // 亡灵类怪物 class M_Undead : public Monster { public: // 构造函数 M_Undead(int life, int magic, int attack) : Monster(life, magic, attack) { cout << "一个亡灵类怪物来到了这个世界" << endl; } // 其他代码略 }; // 元素类怪物 class M_Element : public Monster { public: // 构造函数 M_Element(int life, int magic, int attack) : Monster(life, magic, attack) { cout << "一个元素类怪物来到了这个世界" << endl; } // 其他代码略 }; // 机械类怪物 class M_Mechanic : public Monster { public: // 构造函数 M_Mechanic(int life, int magic, int attack) : Monster(life, magic, attack) { cout << "一个机械类怪物来到了这个世界" << endl; } // 其他代码略 }; // 所有工厂类的父类 class M_ParFactory { public: virtual Monster* createMonster() = 0; // 具体实现在子类中进行 virtual ~M_ParFactory() {} // 父类的析构函数应该为虚函数 }; // M_Undead怪物类型的工厂,生产M_Undead类型怪物 class M_UndeadFactory : public M_ParFactory { public: virtual Monster* createMonster() { Monster *ptmp = new M_Undead(300, 50, 80); // 创建亡灵类怪物 //这里可以增加一些其他业务代码 return ptmp; } }; // M_Element怪物类型的工厂,生产M_Element类型怪物 class M_ElementFactory : public M_ParFactory { public: virtual Monster* createMonster() { return new M_Element(200, 80, 100); // 创建元素类怪物 } }; // M_Mechanic怪物类型的工厂,生产M_Mechanic类型怪物 class M_MechanicFactory : public M_ParFactory { public: virtual Monster* createMonster() { return new M_Mechanic(400, 0, 110); // 创建机械类怪物 } }; // 全局函数:用于创建怪物对象 // 注意:形参的类型是工厂父类类型的指针,返回类型是怪物父类类型的指针 Monster* Gbl_CreateMonster(M_ParFactory* factory) { return factory->createMonster(); // createMonster虚函数扮演了多态new的行为,factory指向的具体怪物工厂类不同,创建的怪物对象也不同 } int main() { M_ParFactory* p_ud_fy = new M_UndeadFactory(); // 多态工厂,注意指针类型 Monster* pM1 = Gbl_CreateMonster(p_ud_fy); // 产生了一只亡灵类怪物,也是多态,注意返回类型 // 当然,这里也可以直接写成 Monster *pM1 = p_ud_fy->createMonster(); M_ParFactory* p_elm_fy = new M_ElementFactory(); Monster *pM2 = Gbl_CreateMonster(p_elm_fy); // 产生了一只元素类怪物 M_ParFactory* p_mec_fy = new M_MechanicFactory(); Monster* pM3 = Gbl_CreateMonster(p_mec_fy); // 产生了一只机械类怪物 // 释放工厂 delete p_ud_fy; delete p_elm_fy; delete p_mec_fy; // 释放怪物 delete pM1; delete pM2; delete pM3; return 0; }
简单工厂模式把创建对象这件事放到了一个统一的地方来处理,弹性比较差。而工厂方法模式相当于建立了一个程序实现框架,从而让子类来决定对象如何创建。
工厂方法模式往往需要创建一个与产品等级结构(层次)相同的工厂等级结构,这也增加了新类的层次结构和数目。
如果不想创建太多工厂类,又想封装变化,则可以创建怪物工厂子类模板。
#include <iostream> using namespace std; // 怪物父类 class Monster { public: // 构造函数 Monster(int life, int magic, int attack) : m_life(life), m_magic(magic), m_attack(attack) {} virtual ~Monster() {} // 父类的析构函数应该为虚函数 protected: // 可能被子类访问的成员,所以用protected修饰 int m_life; // 生命值 int m_magic; // 魔法值 int m_attack; // 攻击力 }; // 亡灵类怪物 class M_Undead : public Monster { public: // 构造函数 M_Undead(int life, int magic, int attack) : Monster(life, magic, attack) { cout << "一个亡灵类怪物来到了这个世界" << endl; } // 其他代码略 }; // 元素类怪物 class M_Element : public Monster { public: // 构造函数 M_Element(int life, int magic, int attack) : Monster(life, magic, attack) { cout << "一个元素类怪物来到了这个世界" << endl; } // 其他代码略 }; // 机械类怪物 class M_Mechanic : public Monster { public: // 构造函数 M_Mechanic(int life, int magic, int attack) : Monster(life, magic, attack) { cout << "一个机械类怪物来到了这个世界" << endl; } // 其他代码略 }; // 所有工厂类的父类 class M_ParFactory { public: virtual Monster* createMonster() = 0; // 具体实现在子类中进行 virtual ~M_ParFactory() {} // 父类的析构函数应该为虚函数 }; template <typename T> class M_ChildFactory :public M_ParFactory { public: virtual Monster* createMonster() { return new T(300, 50, 80); //如果需要不同的值则可以通过createMonster的形参将值传递进来 } }; int main() { M_ChildFactory<M_Undead> myFactory; Monster* pM10 = myFactory.createMonster(); // 释放资源 delete pM10; getchar(); return 0; }
UML 如下:
2.工厂方法模式的定义(实现意图)
定义一个用于创建对象的接口(M_ParFactory类中的createMonster成员函数),由子类(M_UndeadFactory
、M_ElementFactory
、M_MechanicFactory
)决定要实例化的类是哪一个。该模式使得某个类(M_Undead
、M_Element
、M_Mechanic
)的实例化延迟到子类(M_UndeadFactory
、M_ElementFactory
、M_MechanicFactory
)。
一般可以认为,将简单工厂模式的代码经过把工厂类进行抽象改造成符合开闭原则后的代码,就变成了工厂方法模式的代码。