如今做哪些网站能致富,营销型网站设计方针,微信公众号公众平台,wordpress中文验证码简单工厂#xff08;Simple Factory#xff09;模式 我们从实际例子出发#xff0c;来看在什么情况下#xff0c;应用简单工厂模式。
还是以一个游戏举例 //策划#xff1a;亡灵类怪物#xff0c;元素类怪物#xff0c;机械类怪物#xff1a;都有生命值#xff0…简单工厂Simple Factory模式 我们从实际例子出发来看在什么情况下应用简单工厂模式。
还是以一个游戏举例 //策划亡灵类怪物元素类怪物机械类怪物都有生命值魔法值攻击力三个属性。 //Monster作为父类M_Undead亡灵类M_Element元素类怪物M_Mechanic机械类怪物。 一般写法如下
#include iostream
using namespace std;//1简单工厂Simple Factory模式
//策划亡灵类怪物元素类怪物机械类怪物都有生命值魔法值攻击力三个属性。
//Monster作为父类M_Undead亡灵类M_Element元素类怪物M_Mechanic机械类怪物。namespace _namespace1 {class Monster {public:Monster(int life, int magic, int attack) : m_life(life), m_magic(magic), m_attack(attack){};virtual ~Monster() {};protected:int m_life;int m_magic;int m_attack;};//M_Undead亡灵类class M_Undead :public Monster {public:M_Undead(int life, int magic, int attack) :Monster(life, magic, attack) {cout 创建了一个亡灵类 life m_life magic m_magic attack m_attack endl;}};//M_Element元素类怪物class M_Element :public Monster {public:M_Element(int life, int magic, int attack) :Monster(life, magic, attack) {cout 创建了一个元素类怪物 life m_life magic m_magic attack m_attack endl;}};//M_Mechanic机械类怪物class M_Mechanic :public Monster {public:M_Mechanic(int life, int magic, int attack) :Monster(life, magic, attack) {cout 创建了一个机械类怪物 life m_life magic m_magic attack m_attack endl;}};};void normalTest() {_namespace1::Monster *pm1 new _namespace1::M_Undead(1, 2, 3);_namespace1::Monster *pm2 new _namespace1::M_Element(4, 5, 6);_namespace1::Monster *pm3 new _namespace1::M_Mechanic(7, 8, 9);delete pm1;delete pm2;delete pm3;}int main()
{_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口//不使用工厂模式的一般写法normalTest();std::cout Hello World!\n;
} 问题
那么这个不使用工厂模式的一般写法有啥问题呢或者说有啥缺点呢 //假设我们在每一个关卡都要 new 出来这些实例对象。 //有一天策划找到我们说机械怪物的生命力要加1,我们能想到的合适的办法是 //将怪物的参数做成配置文件游戏加载时候就将配置文件读取成一个一个的全局变量然后new 的时候用这些全局变量 //有一天策划又找到我们说怪物还应该有个盔甲,鞋子,帽子,武器,盾牌这些属性 //那我们就要改动构造方法了这个不改不行了又因为我们在每一关都要new出来这些怪物因此每个关卡的代码都要改动。 //言外之意是这种普通的写法 new 具体类名来创建对象是一种 依赖具体类型的紧耦合关系 解决方案 那么怎么改动才合理呢引入简单工厂模式 //工厂模式通过把创建对象的代码包装起来做到创建对象的代码与具体的业务逻辑代码相隔离的目的。 #include iostream
using namespace std;//1简单工厂Simple Factory模式
//策划亡灵类怪物元素类怪物机械类怪物都有生命值魔法值攻击力三个属性。
//Monster作为父类M_Undead亡灵类M_Element元素类怪物M_Mechanic机械类怪物。namespace _namespace1 {class Monster {public:Monster(int life, int magic, int attack) : m_life(life), m_magic(magic), m_attack(attack){};virtual ~Monster() {};protected:int m_life;int m_magic;int m_attack;};//M_Undead亡灵类class M_Undead :public Monster {public:M_Undead(int life, int magic, int attack) :Monster(life, magic, attack) {cout 创建了一个亡灵类 life m_life magic m_magic attack m_attack endl;}};//M_Element元素类怪物class M_Element :public Monster {public:M_Element(int life, int magic, int attack) :Monster(life, magic, attack) {cout 创建了一个元素类怪物 life m_life magic m_magic attack m_attack endl;}};//M_Mechanic机械类怪物class M_Mechanic :public Monster {public:M_Mechanic(int life, int magic, int attack) :Monster(life, magic, attack) {cout 创建了一个机械类怪物 life m_life magic m_magic attack m_attack endl;}};const int UndeadType 1;const int ElementType 2;const int MechanicType 3;//简单工厂模式,怪物工厂class MonsterFactory {public:Monster * createMonster(int monstertype) {Monster * tempPM nullptr;switch (monstertype){case UndeadType://UndeadType,ElementType,MechanicType都是程序员定义的表示怪物类型的值//1,2,3可以来源于从配置文件读取的值//我们可以将 new M_Undead的代码全部都写在这里//如果策划要改动构造方法给构造方法里面加上盔甲,鞋子,帽子,武器,盾牌这些属性//我们只需要在这里改动无需在业务逻辑层面改动构造方法。tempPM new M_Undead(11, 22, 33);break;case ElementType:tempPM new M_Element(44,55,66);//提示如果元素怪物有额外的属性或者参数也可以在这里设置//tempPM.setxxx(xxx);break;case MechanicType:tempPM new M_Mechanic(77,88,99);break;default:return tempPM;break;}//注意switch case 使用时候的 这个warning 提示3 c:\users\administrator\source\repos\designpattern\002simplefactory\002simplefactory.cpp(80) : warning C4715 : “_namespace1::MonsterFactory::createMonster” : 不是所有的控件路径都返回值//解决方案是加上如下的这一样return tempPM;}};
};void normalTest() {_namespace1::Monster *pm1 new _namespace1::M_Undead(1, 2, 3);_namespace1::Monster *pm2 new _namespace1::M_Element(4, 5, 6);_namespace1::Monster *pm3 new _namespace1::M_Mechanic(7, 8, 9);delete pm1;delete pm2;delete pm3;}void simpleFactoryTest() {_namespace1::MonsterFactory monsfactory;_namespace1::Monster *pm4 monsfactory.createMonster(_namespace1::UndeadType);_namespace1::Monster *pm5 monsfactory.createMonster(_namespace1::ElementType);_namespace1::Monster *pm6 monsfactory.createMonster(_namespace1::MechanicType);delete pm4;delete pm5;delete pm6;
}int main()
{_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口//不使用工厂模式的一般写法normalTest();//那么这个不使用工厂模式的一般写法有啥问题呢//或者说有啥缺点呢//假设我们在每一个关卡都要 new 出来这些实例对象。//有一天策划找到我们说机械怪物的生命力要加1,我们能想到的合适的办法是//将怪物的参数做成配置文件游戏加载时候就将配置文件读取成一个一个的全局变量然后new 的时候用这些全局变量//有一天策划又找到我们说怪物还应该有个盔甲,鞋子,帽子,武器,盾牌这些属性//那我们就要改动构造方法了这个不改不行了又因为我们在每一关都要new出来这些怪物因此每个关卡的代码都要改动。//言外之意是这种普通的写法 new 具体类名来创建对象是一种 依赖具体类型的紧耦合关系//那么怎么改动才合理呢引入简单工厂模式//工厂模式通过把创建对象的代码包装起来做到创建对象的代码与具体的业务逻辑代码相隔离的目的。simpleFactoryTest();//从上面的代码可以看到简单工厂模式确实实现了new 出来具体对象 和 业务逻辑的分离//但是不符合 开闭原则//开闭原则说的是代码扩展性问题——对扩展开放对修改关闭封闭//假设过了两天策划找到我们说加一种怪物新怪物类型M_Beast野兽类//那我们要怎么改呢首先肯定是加一个 M_Beast类了继承Monster//然后MonsterFactory 中改动 createMonster方法完成。//很显然我们要改动到原先的 createMonster 方法这是违反了 开闭原则的。//那么如何改动才合理呢这就要用到 工厂方法 模式std::cout Hello World!\n;
} 遗留问题 //从上面的代码可以看到简单工厂模式确实实现了new 出来具体对象 和 业务逻辑的分离 //但是不符合 开闭原则 //开闭原则说的是代码扩展性问题——对扩展开放对修改关闭封闭 //假设过了两天策划找到我们说加一种怪物新怪物类型M_Beast野兽类 //那我们要怎么改呢首先肯定是加一个 M_Beast类了继承Monster //然后MonsterFactory 中改动 createMonster方法完成。 //很显然我们要改动到原先的 createMonster 方法这是违反了 开闭原则的。 //那么如何改动才合理呢这就要用到 工厂方法 模式 简单工厂的UML 图