一、简单工厂模式
考虑这样一个场景,王者荣耀的英雄池里面有很多英雄类,当选择一个英雄的时候,就相当于实例化了一个类对象,比如 new 亚瑟,new 妲己……传统的方法是在顶层直接调用 new+类名 来构造一个对象,但是如果类的构造过程十分复杂,而顶层逻辑并不关心具体的构造过程,就可以使用工厂模式。创建一个工厂类,其有一个create函数,根据传入的参数不同,返回不同的对象。
#include <iostream>
using namespace std;
//抽象英雄类
class AbstractHero
{
public:
virtual void showName() {};
};
//百里守约类
class BaiLiShouYueHero :public AbstractHero
{
public:
virtual void showName() {
cout << "百里守约" << endl;
};
};
//妲己类
class DaJiHero :public AbstractHero
{
public:
virtual void showName() {
cout << "妲己" << endl;
};
};
//李白类
class LiBaiHero :public AbstractHero
{
public:
virtual void showName() {
cout << "李白" << endl;
};
};
//工厂类
class Factory
{
public:
AbstractHero* createHero(string name)
{
if (name == "百里守约")
{
return new BaiLiShouYueHero;
}
else if (name == "妲己")
{
return new DaJiHero;
}
else if (name == "李白")
{
return new LiBaiHero;
}
else
return NULL;
};
};
int main()
{
Factory* factory = new Factory;
AbstractHero* hero = factory->createHero("百里守约");
hero->showName();
delete hero;
hero = factory->createHero("妲己");
hero->showName();
delete hero;
hero = factory->createHero("李白");
hero->showName();
delete hero;
}
可见,工厂模式有以下优点:
1、逻辑层与底层解耦
2、客户端不必关心复杂的底层构造过程
3、适用于对象比较少的情况
缺点:
1、不符合开闭原则,增加一个英雄就要修改工厂类的代码
2、不符合单一职责原则,这个工厂类发生问题时候,会影响很多地方
二、工厂方法模式
简单工厂模式有弊端,即他不符合开闭原则和单一职责原则
那么只要设计一个抽象工厂类,再用 百里守约工厂类 ,李白工厂类,继承于抽象工厂类,这样就实现了工厂方法模式,也符合开闭原则和单一职责原则。
但毫无疑问,这种方法大大增加了代码量,增加抽象性和理解难度,这也是我最困惑的地方,这不累吗?
#include <iostream>
using namespace std;
//抽象英雄类
class AbstractHero
{
public:
virtual void showName() {};
};
//百里守约类
class BaiLiShouYueHero :public AbstractHero
{
public:
virtual void showName() {
cout << "百里守约" << endl;
};
};
//妲己类
class DaJiHero :public AbstractHero
{
public:
virtual void showName() {
cout << "妲己" << endl;
};
};
//李白类
class LiBaiHero :public AbstractHero
{
public:
virtual void showName() {
cout << "李白" << endl;
};
};
//抽象工厂类
class AbstractFactory
{
public:
virtual AbstractHero* createHero()=0;
};
//百里守约工厂类
class BaiLiShouYueFactory :public AbstractFactory
{
public:
AbstractHero* createHero()
{
return new BaiLiShouYueHero;
};
};
//妲己工厂类
class DaJiFactory :public AbstractFactory
{
public:
AbstractHero* createHero()
{
return new DaJiHero;
};
};
//李白工厂类
class LiBaiFactory :public AbstractFactory
{
public:
AbstractHero* createHero()
{
return new LiBaiHero;
};
};
int main()
{
AbstractFactory* factory = new BaiLiShouYueFactory;
AbstractHero* hero = factory->createHero();
hero->showName();
delete hero;
delete factory;
factory = new DaJiFactory;
hero = factory->createHero();
hero->showName();
delete hero;
delete factory;
factory = new LiBaiFactory;
hero = factory->createHero();
hero->showName();
delete hero;
}
三、抽象工厂模式
考虑如下情景:
在前文中,我们已经创建了各种创建英雄的工厂,但一局游戏有十个人,玩家A选择的英雄,跟玩家B选择的英雄是不一样的,即使他们全部选择妲己,这几个妲己也是妲己A,妲己B……那怎么区分呢?
抽象工厂模式:针对产品族,而不是产品等级。
产品族:同一个来源,不同功能。如玩家A创建了妲己A,又创建了百里守约A。
产品等级:同一个功能,不同来源。如玩家A,玩家B创建了妲己A,妲己B。
抽象工厂,即把工厂作为抽象类,派生出玩家A工厂,玩家B工厂,这时如果新加入了玩家C,只需要再派生一个玩家C工厂即可,对于产品族的扩展,是符合开闭原则的;
但是对于产品等级则不符合开闭原则。假如要新增一个英雄露娜,就需要修改所有的工厂代码。
抽象工厂代码太多,就不放了,讲一讲思路。
1、抽象出一个抽象百里守约、抽象李白、抽象妲己类;
2、这三个类派生出玩家A的百里守约,玩家B的百里守约,玩家A的李白……等等
3、抽象出一个抽象工厂类;
4、派生出玩家A的工厂,玩家B的工厂。
四、单例模式
考虑如下情景:
在系统中,某些类只允许存在一个实例,比如任务管理器的窗口,只能有一个,这个情况就是单例模式。步骤如下:
1、构造函数私有化
2、声明一个静态私有成员变量,类型为该类
3、类外初始化该私有变量
4、提供一个静态的对外接口
#include <iostream>
using namespace std;
class Task
{
private:
Task() {}
public:
static Task *getInstance()
{
if (mTask == NULL)
{
mTask = new Task();
}
return mTask;
}
private:
static Task *mTask;
};
Task* Task::mTask = NULL;
int main()
{
Task* p1 = Task::getInstance();
return 0;
}
上面创建的是一个懒汉式单例,因为这个单例是在main函数执行之后才调用构造函数的,看起来比较懒,所以叫懒汉式,下面写一个饿汉式
class Task_hungry
{
private:
Task_hungry() {}
static Task_hungry* mTask;
public:
static Task_hungry* getInstance()
{
return mTask;
}
};
Task_hungry* Task_hungry::mTask = new Task_hungry;
饿汉式的构造函数会在main之前就调用,看起来很饿,所以叫饿汉式
单例销毁问题:单例的一般不提供销毁接口。