Simple Factory模式根据提供给它的数据,返回几个可能类中的一个类的实例,通常这个类都有一个公共的父类和一些公共的方法。需要说明的是Simple Factory模式并非GoF所定义的23个设计模式中的一员。
在国外,关于一个人的全名,通常有两种写法:一个人的姓名,如果中间有“,”,则姓在前,名在后;如果中间没有“,”,那么空格前为名,后为姓。比如:“Bill Gates”,那么Bill就是名,Gates就是姓;“Clinton, Bill”,那么Clinton就是姓,Bill就是名。
现在假定有一个问题:随机用上述两种不同的方式输入全名,用程序区分其姓和名。对于这样的问题,用Simple Factory模式来解决是很方便的。
下图就用Simple Factory模式解决这个问题的类图:
下面是在C++中的具体实现:
// SimpleNameFactory.h
#include <string>
#include <memory>
#include <iostream>
using namespace std;
// 这是一个和模式无关的工具类
class PatUtility
{
public:
string& trim(string& s); // 用来删除一个字符串前面或者后面的空格
};
// 公共父类。在C++中,
// 1. 父类的析构函数一般必须是virtual的
// 2. 准备被子类重写的成员函数,也必须是virtual的
class FullNamer
{
public:
virtual string getLastName();
virtual string getFirstName();
virtual ~FullNamer()
{
cout << "in the destructor of FullNamer" << endl;
}
protected:
string last_name;
string first_name;
};
// 名在前
class FirstNameFirst : public FullNamer
{
public:
FirstNameFirst(const string& str);
~FirstNameFirst()
{
cout << "in destructor of FNF" << endl;
}
};
// 姓在前
class LastNameFirst : public FullNamer
{
public:
LastNameFirst(const string&);
~LastNameFirst()
{
cout << "in destructor of LNF" << endl;
}
};
// 简单工厂类
class NameSimpleFactory
{
public:
// 返回类型是auto_ptr<FullNamer>,它可以理解为可以自动
// 销毁对象的FullNamer*
auto_ptr<FullNamer> createFullNamer(const string&);
};
// SimpleNameFactory.cpp
#include "SimpleNameFactory.h"
// 删除一个字符串前面和后面的空白
string& PatUtility::trim(string& s)
{
if(s.empty()) return s;
s.erase(0, s.find_first_not_of(" "));
s.erase(s.find_last_not_of(" ") + 1);
return s;
}
// 返回名
string FullNamer::getFirstName()
{
return first_name;
}
// 返回姓
string FullNamer::getLastName()
{
return last_name;
}
// FirstNameFirst类的构造函数
FirstNameFirst::FirstNameFirst(const string& str)
{
PatUtility pu;
// 名在前,空格符为分隔符
size_t i = str.find_last_of(" ");
if(i != string::npos)
{
first_name = pu.trim(str.substr(0, i));
last_name = pu.trim(str.substr(i + 1));
}
else
{
first_name = "";
last_name = str;
}
}
// LastNameFirst类的构造函数
LastNameFirst::LastNameFirst(const string& str)
{
PatUtility pu;
// 姓在前,逗号为分隔符
size_t i = str.find_last_of(",");
if(i != string::npos)
{
first_name = pu.trim(str.substr(i + 1));
last_name = pu.trim(str.substr(0, i));
}
else
{
first_name = "";
last_name = str;
}
}
auto_ptr<FullNamer> NameSimpleFactory::createFullNamer(const string& entry)
{
size_t i = entry.find_last_of(",");
// 在下面的if语句中,决定了到底返回那个类的实例,这就是Simple Factory
// 模式的控制中枢所在
if(i != string::npos) // 如果提供的全名包含“,”
{
// 如果不使用auto_ptr,那么通过new LastNameFirst(entry)动态分配到
// 内存不会自动释放
auto_ptr<FullNamer> p(new LastNameFirst(entry));
return p;
}
else // 如果提供的全名不包含“,”
{
auto_ptr<FullNamer> p(new FirstNameFirst(entry));
return p;
}
}
// 测试代码
#include "SimpleNameFactory.h"
int main(void)
{
// 定义一个NameSimpleFactory对象
NameSimpleFactory nsf;
string entry1("CLINTON, BILL");
// 如果不考虑自动内存释放,下面的语句类似于(当然实际上这么做事不行的,除非createFullNamer
// 返回类型为FullNamer*,除此之外,当fn1使用完成后,要delete fn1;,否则会有内存泄漏):
// FullNamer *fn1 = nsf.createFullNamer(entry1);
auto_ptr<FullNamer> fn1(nsf.createFullNamer(entry1));
cout << "First name is: " << fn1->getFirstName() << ", and last name is: " << \
fn1->getLastName() << endl;
string entry2("BILL GATES");
auto_ptr<FullNamer> fn2(nsf.createFullNamer(entry2));
cout << "First name is: " << fn2->getFirstName() << ", and last name is: " << \
fn2->getLastName() << endl;
return 0;
}
上面的程序运行结果:
First name is: BILL, and last name is: CLINTON
First name is: BILL, and last name is: GATES
in destructor of FNF
in the destructor of FullNamer
in destructor of LNF
in the destructor of FullNamer
输出结果符合预期。
Simple Factory的优点和缺点:
优点:客户端程序无需知道返回具体类的实例,这项工作全部由Factory类去完成,这就隔离了客户端代码。
缺点:要返回哪个类是由Factory类来决定的,因此,比如当增加一个具体类时,Factory代码必须改动。