工厂模式是最常用的创建型模式之一,在开始工厂模式之前,我们先来看一个场景,假如要设计一个电脑类,生成的电脑对象要包含CPU,那么可能有人会这么设计:
class PC
{
private:
string m_CPU;
public:
PC(string nPCName)
{
if("Apple" == nPCName)
{
m_CPU = "Apple_CPU";
}
else if("Dell" == nPCName)
{
m_CPU = "Dell_CPU";
}
}
string getCPU()
{
return m_CPU;
}
};
这里举的例子中假设苹果电脑用自己CPU,戴尔电脑用自己的CPU(当然也可能是第三方的CPU),然后按照下边的方式使用
int main(int argc, char* argv[])
{
PC ApplePC("Apple");
cout << ApplePC.getCPU() << endl;
return 0;
}
可以得到输出的CPU是苹果的,但是这里个问题是,假如有一天要生成HP电脑,那么我们就必须要改PC类,在里边增加else if("HP" == nPCName){HP电脑初始化},这就导致了每增加一个电脑品牌,都要在PC类中做修改,这违背了设计模式中的开闭原则。
为了解决上面的问题,我们引出标题中的简单工厂模式,在简单工厂模式中,我们要引入三个角色:
1、Factory(工厂角色):工厂角色是简单工厂模式的核心,负责创建所有产品实例,返回的是抽象产品类型(见第2点)
2、Product(抽象产品角色):作为所有产品类的父类封装了产品类的共有方法。
3、ConcreteProduct(具体产品角色):继承自抽象产品角色而创建的实实在在的目标,并实现了抽象产品角色中的共有方法。
有了以上三点,我们来改造下我们的代码:
首先创建一个电脑的产品类(包括PC抽象类、PC具体类),抽象类中接口为获取CPU的纯虚函数
//PC的抽想产品类
class PC
{
public:
virtual string getCPU() = 0;
};
//具体PC类:Apple电脑,继承自PC抽象类
class ApplePC : public PC
{
public:
string getCPU()
{
return "AppleCPU";
}
};
//具体PC类:Dell电脑,继承自PC抽象类
class DellPC : public PC
{
public:
string getCPU()
{
return "DellCPU";
}
};
接着来创建简单工厂的核心部分:工厂类(要点为返回的值为抽象产品类,才能实现多态)
class PCFactory
{
public:
//这里设为静态函数的目的是可以直接通过类名::createPC调用,不需要实例化工厂对象
//需要注意的是:返回值为产品的抽象类(这里为电脑抽象类PC)
static PC* createPC(string nPCName)
{
if("Apple" == nPCName)
{
return new ApplePC;
}
else if("Dell" == nPCName)
{
return new DellPC;
}
}
};
到这里,我们的简单工厂模式已经设计完成,使用如下:
int main(int argc, char* argv[])
{
PC* pPC = PCFactory::createPC("Apple");
cout << pPC->getCPU() << endl;
return 0;
}
简单工厂模式在一定程度上解决了问题, 但是细心的朋友会发现,当我们需要增加HP电脑时,就需要更改PCFactory工厂类中的方法,也就是说每次更改增加一个电脑,就要重新编译客户端的工厂类。
导致 这个问题的原因就是:简单工厂模式所有的产品都由同一个工厂生产,那有没有可能是设置一个只负责下命名的总工厂,而生产产品的工作由各个子工厂完成,答案是肯定的,这就是即将要说的工厂模式。其实这 跟企业的管理模式有异曲同工之妙,总部只负责下达命令我要生产什么,具体生产执行则由各个工厂去完成。
现在来看看工厂模式需要的几个要素
1、Factory(抽象工厂角色):抽象工厂角色是工厂模式的核心,声明公共的创建方法(即指令),具体工厂要继承抽象工厂并实现接口。
2、ConcreteFactory(具体工厂角色):继承抽象工厂,实现创建接口创建具体的产品
3、Product(抽象产品角色):作为所有产品类的父类封装了产品类的共有方法。
4、ConcreteProduct(具体产品角色):继承自抽象产品角色而创建的实实在在的目标,并实现了抽象产品角色中的共有方法。
//抽象产品(电脑)
class PC
{
public:
virtual string getCPU() = 0;
};
//具体产品(Apple电脑)
class ApplePC : public PC
{
public:
string getCPU()
{
return "AppleCPU";
}
};
//具体产品(Dell电脑)
class DellPC : public PC
{
public:
string getCPU()
{
return "DellCPU";
}
};
//抽象工厂(工厂总部)
class Factory
{
public:
virtual PC* createPC() = 0;
};
//具体工厂(Apple工厂)
class AppleFactory : public Factory
{
public:
PC* createPC()
{
return new ApplePC;
}
};
//具体工厂(Dell工厂)
class DellFactory : public Factory
{
public:
PC* createPC()
{
return new DellPC;
}
};
int main(int argc, char* argv[])
{
Factory* f = new DellFactory; //下达指令到Dell工厂(要生产Dell电脑)
PC* pPC = f->createPC(); //Dell工厂生产电脑
cout << pPC->getCPU() << endl; //使用具体的产品
return 0;
}
到这,工厂模式就结束了,但是需求会回来越多,假如我要使用电脑、手机两个设备连成一个家庭套餐使用。那就有可能不同品牌间的手机电脑无法正常连接或者使用体验不好。比方我们用的电脑时Apple的,但是手机是HW,那么他们的使用体验可能就不那么友善了。
为了解决这个问题,我们引出了工厂模式中的最后一种:抽象工厂
抽象工厂解决的问题属于创建一个产品族,举个例子就是工厂里生产苹果电脑、苹果手机、苹果手环等等,生产出来的家族产品可以很吻合的配合使用。(这里应该把抽象工厂定义成家族工厂是不是更合适些?嘿嘿嘿...)
有了以上工厂模式的基础,抽象工厂就很简单了,现在工厂只生产电脑,那么我们直接把手机产品线也放进去好了,得到的结果就是生产出来的要么是ApplePC+iPhone,要么是DellPC+DPhnoe(额。。自己开创品牌),抬椅子上马:
//抽象产品(电脑)
class PC
{
public:
virtual string getCPU() = 0;
};
//具体产品(Apple电脑)
class ApplePC : public PC
{
public:
string getCPU()
{
return "AppleCPU";
}
};
//具体产品(Dell电脑)
class DellPC : public PC
{
public:
string getCPU()
{
return "DellCPU";
}
};
//抽象产品(手机)
class Phone
{
public:
virtual string call() = 0;
};
//具体产品(iPhone)
class iPhone : public Phone
{
public:
string call()
{
return "iPhone du...du...";
}
};
//具体产品(DPhone)
class DPhone : public Phone
{
public:
string call()
{
return "DPhone du...du...";
}
};
//抽象工厂(工厂总部)
class Factory
{
public:
virtual PC* createPC() = 0;
virtual Phone* createPhone() = 0;
};
//具体工厂(Apple工厂)
class AppleFactory : public Factory
{
public:
PC* createPC()
{
return new ApplePC;
}
Phone* createPhone()
{
return new iPhone;
}
};
//具体工厂(Dell工厂)
class DellFactory : public Factory
{
public:
PC* createPC()
{
return new DellPC;
}
Phone* createPhone()
{
return new DPhone;
}
};
int main(int argc, char* argv[])
{
Factory* f = new AppleFactory; //下达指令到Apple工厂(要生产Apple系列产品)
PC* pPC = f->createPC(); //Apple工厂生产Apple mac
Phone* pPhone = f->createPhone(); //Apple工厂生产iPhone
cout << pPC->getCPU() << endl; //使用Apple Mac
cout << pPhone->call() << endl;//使用iPhone
return 0;
}
到此,工厂模式的三种类型都讲完了。