一、简单工厂模式概述
简单工厂模式包含以下角色:
1. Factory(工厂角色):它是工厂模式的核心,负责创建所有实例的内部逻辑;工厂类可以直接被外界调用,创建所需要的产品对象;可以在工厂类中提供静态的工厂方法,返回一个抽象产品类Product,所有的具体产品都是抽象产品的子类。
2. Product(抽象产品角色):抽象产品角色是简单工厂模式所创建的所有对象的父类,负责描述所有实例所共有的公共接口。
3. ConcreteProduct(具体产品角色):具体产品角色是工厂模式的创建目标,所有创建的对象都充当这个角色的某个具体类的实例,每个具体产品角色都继承了抽象产品角色,需要实现定义在抽象产品中的抽象方法。
下面是简单工厂方法模式的结构图:
一、简单工厂模式实例
例1. 下面就我用C++来写个程序来实现一个这种模式的例子。在此程序中,Calculate_Factory类充当工厂的角色。在main()函数里, createObject(char)函数会根据它接收到的参数,创建相应的对象(产品),然后返回这个对象(return),即生成哪个对象是根据createObject(char)函数的参数来决定的了,而这个参数是由用户输入的。剩下的几个类Calculate_Add、Calculate_Sub、Calculate_Mul、Calculate_Div就是负责生产具体产品的类了。最后一个类是Calculate_Base,这个类相当于一个仓库,这个仓库里有各具体产品类的公共生产工具。为了简明起见,我用加减乘除来代替实际的生产过程。下面先给出程序类图的UML描述:
下面是这个模式实例的C++实现源码:
#include<iostream>
using namespace std;
//This is the base class of the computing operations
class Calculate_Base
{
public:
virtual double getResult(double op1, double op2)
{
double result = 0;
return result;
}
protected:
double operand_1;
double operand_2;
};
//This class implements the addition operation
class Calculate_Add:public Calculate_Base
{
public:
virtual double getResult(double op1, double op2)
{
return op1 + op2;
}
};
//This class implements the subtraction operation
class Calculate_Sub:public Calculate_Base
{
public:
virtual double getResult(double op1, double op2)
{
return op1 - op2;
}
};
//This class implements the multiplication operation
class Calculate_Mul:public Calculate_Base
{
public:
virtual double getResult(double op1, double op2)
{
return op1 * op2;
}
};
//This class implements the division operation
class Calculate_Div:public Calculate_Base
{
public:
virtual double getResult(double op1, double op2)
{
if(0 == op2)
{
printf("Illegal input!\n");
exit(0);
}
return op1 / op2;
}
};
class Calculate_Factory
{
public:
static Calculate_Base *createObject(char op)
{
switch(op)
{
case '+':
return new Calculate_Add();
case '-':
return new Calculate_Sub();
case '*':
return new Calculate_Mul();
case '/':
return new Calculate_Div();
default:
return new Calculate_Base();
}
}
};
int main()
{
double op1, op2;
char op;
cout << "Please input the computational expressions:";
cin >> op1 >> op >> op2;
Calculate_Base *oper = Calculate_Factory::createObject(op);
cout << endl << "The Calculate result is: " << oper->getResult(op1, op2) << endl;
cout << endl;
//In the end, don't forget to release the memory
delete oper;
oper = NULL;
return 0;
}
例2. 相信说到这里,我们对简单工厂模式已经理解得差不多了。但是实践是检验真理的唯一标准,所以在此我还要举个例子来加深一下我们对简单工厂模式的认识:设想一下,如果现在我们有一个OA系统,用户登录系统时,系统要根据用户输入的账号和密码与存储在数据库中的账号密码进行对比,如果验证通过,则根据不同的用户权限来创建不同的用户对象。我们可以用简单工厂模式来设计该权限管理模块。话不多说,下面来看一下这个模块的类图:
Here is the src code of this demo
(1)Abstract product class
package cn.lion.org;
public abstract class User {
public void sameOperation()
{
System.out.println("Moddify personal information.");
}
public abstract void diffOperation();
}
(2)Specificproducts class(Employee class)
package cn.lion.org;
public class Employee extends User{
public Employee()
{
System.out.println("Create employee object.");
}
public void diffOperation()
{
System.out.println("Employee's operation.");
}
}
(3)Specificproducts class(Manager class)
package cn.lion.org;
public class Manager extends User{
public Manager()
{
System.out.println("Create Manager object.");
}
public void diffOperation()
{
System.out.println("Manager's operation.");
}
}
(4)Specificproducts class(Administrator class)
package cn.lion.org;
public class Administrator extends User{
public Administrator()
{
System.out.println("Create Administrator object.");
}
public void diffOperation()
{
System.out.println("Administrator's operation.");
}
}
(5)Factoryclass(UserFactory class)
package cn.lion.org;
public class UserFactory {
public static User getUser(int permission)
{
if(0 == permission)
{
return new Employee();
}
else if(1 == permission)
{
return new Manager();
}
else if(2 == permission)
{
return new Administrator();
}
else
{
return null;
}
}
}
(6)Access to the user database class(UserDao class), for convenience, Iuse a simple class instead the real UserDao class
package cn.lion.org;
public class UserDao {
public int getPermission(String uName, String uPwd)
{
if("lion" == uName && "0000" == uPwd)
{
return 0;
}
else
{
return -1;
}
}
}
(7)The clienttest class(TestClient class), in this class, we simulated the real users loginthe system. However, in the real development, the users account and passwordcomes from the presentation layer(such as text box and password box or in theform of a web page).
package cn.lion.org;
public class TestClient {
public static void main(String args[])
{
try
{
User user;
UserDao userDao = new UserDao();
int permission = userDao.getPermission("lion", "0000");
user = UserFactory.getUser(permission);
user.sameOperation();
user.diffOperation();
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
}
}
三、简单工厂模式的优缺点及适用环境
1.优点:
(1)它可以决定什么时候创建一个产品类的实例,客户端不用直接创建对象,就可以消费产品,因为它提供了专门的工厂类用于创建对象;
(2)客户端无需知道所创建的具体产品类的类名,只要知道具体类对应的参数就行了,这样用户就可以不用记忆复杂的类名了;
(3)通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,提高系统的灵活性。
2.缺点:
(1)因为工厂类集中了所有产品的创建逻辑,所以一旦它不能正常工作,整个系统都要受到影响;
(2)如果要添加新的产品,就不得不修改工厂的逻辑,这不但违背了软件设计的开闭原则,而且当产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护;
(3)因为简单工厂模式使用了静态的工厂方法,所以其角色无法形成基于继承的等级结构。即,虽然子类可以继承和覆盖父类的静态方法,但是如果在定义时使用的是父类,即使实例化的是子类也无法访问子类覆盖后的静态方法,从而导致静态工厂方法的工厂类无法像产品类一样提供抽象层与抽象定义,也无法通过具体类来进行扩展。
3. 该模式的适用环境:工厂类负责创建的对象比较少时,不会造成工厂方法中的业务逻辑太复杂,所以此时可用。JDK类库中的工具类java.text.DateFormat就使用了工厂就法。