面向对象的程序中,对象的创建是一件非常重要的事情。
简单工厂,就是将类的具体对象当做一个个产品,通过一个加工工厂,把这些产品创建出来,简单工厂模式,核心就是这个创建产品的工厂。
这个模式的使用频率非常大。
很多公司,根据员工能力不同,会将员工分为很多级别,不同级别的员工工资不一样。下面就以这个例子(这个例子会一直扩展下去),介绍一下简单工厂。
想实现不同职级不同公司,很容易想到多态。一个员工职级的基类,定义一个虚函数获取工资,不同职级,从这个基类派生,重写获取工资的虚函数。
看代码(visual studio 2019):
#pragma once
#include <iostream>
#include <list>
class GradeBase
{
public:
GradeBase(const std::string& strName) :m_strName(strName) {}
virtual ~GradeBase() = default;
std::string GetName() const { return m_strName; }
virtual double GetSalary() = 0;
protected:
std::string m_strName; //姓名
};
class Grade_1 : public GradeBase
{
public:
using GradeBase::GradeBase;
double GetSalary() override {
return 5000;
}
};
class Grade_2 : public GradeBase
{
public:
using GradeBase::GradeBase;
double GetSalary() override {
return 8000;
}
};
class SimpleFactory
{
public:
static std::unique_ptr<GradeBase> GetLevel(const std::string& strName, int iLevel){
if (1 == iLevel)
return std::make_unique<Grade_1>(strName);
else if (2 == iLevel)
return std::make_unique<Grade_2>(strName);
return nullptr;
}
};
int main()
{
std::list<std::unique_ptr<GradeBase>> lstEmployee;
lstEmployee.push_back(SimpleFactory::GetLevel("David", 1));
lstEmployee.push_back(SimpleFactory::GetLevel("Tom", 2));
lstEmployee.push_back(SimpleFactory::GetLevel("Lucas", 3));
for (const auto& employee : lstEmployee)
{
if (!employee)
continue;
std::cout << employee->GetName() << "薪资:" << employee->GetSalary() << "\n";
}
system("pause");
return 0;
}
以上实现方式,是为了尽可能让代码逻辑简单,有很多不妥,比如直接用等级类来表示职工、未考虑同一员工职级会改变等等,之后会以这个为原型,逐步改进。
基类GradeBase,只有一个变量,表示职工名称,纯虚函数GetSalary获取工资。
不同职级,从GradeBase派生,重写虚函数GetSalary。
SimpleFactory类,就是这个设计模式的核心,提供一个接口,传入职工名称和等级编号,根据编号,用不同的类实例化具体员工。
如果仅仅是这个例子,SimpleFactory存在的必要性不大,因为它的功能完全可以用一个函数替代。类似如下函数:
std::unique_ptr<GradeBase> GetGrade(const std::string& strName, int iLevel)
{
if (1 == iLevel)
return std::make_unique<Grade_1>(strName);
else if (2 == iLevel)
return std::make_unique<Grade_2>(strName);
return nullptr;
}
但是,不要用函数,用类!后面的文章,会对这个类进行扩展,展现简单工厂的真正实用之处。
main函数其实就是客户端,也是调用者,传入不同的员工和等级编号,获取具体的对象。
执行结果如下:
为什么只有两个对象?
因为Lucas传入的等级是3,在GetLevel接口中没有与之对象的创建对象的条件,所以这个对象为nullptr。
这就有个问题了,等级需要扩展怎么办?
简单工厂模式,只能修改GetLevel接口的实现,增加if条件判断,有没有不修改工厂类的方式?当然有,请看下篇文章介绍。