简介
工厂模式是用工厂方法代替new操作的一种模式。它隐藏了复杂的逻辑过程,只关心执行结果。工厂模式分为简单工厂模式、工厂方法模式和抽象工厂模式三种。
简单工厂模式
工厂类实现代码为:
class OperationFactory {
public static Operation createOperate(string Operate) {
Operation oper = null;
switch (oper) {
case "+":
oper = new OperationAdd();
break;
case "-":
oper = new OperationSub();
break;
case "*":
oper = new OperationMul();
break;
case "/":
oper = new OperationDiv();
break;
}
return oper;
}
}
客户端应用代码:
Operation oper;
oper = OperationFactory.createOperate("+");
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();
简单工厂的实现,工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。但问题是,如果我们需要新增一个“求M数的N次方”的功能,我们需要给运算工厂类的方法里加Case的分支条件,修改原有的类,这违背了开放封闭原则,不是一个好的办法。
工厂方法模式
先构建一个工厂接口
interface IFactory {
Operation CreateOperation();
}
然后加减乘除各建一个具体工厂去实现这个接口
class AddFactory : IFactory {
public Operation CreateOperation() {
return new OperationAdd();
}
}
class SubFactory : IFactory {
public Operation CreateOperation() {
return new OperationSub();
}
}
class MulFactory : IFactory {
public Operation CreateOperation() {
return new OperationMul();
}
}
class DivFactory : IFactory {
public Operation CreateOperation() {
return new OperationDiv();
}
}
客户端的实现代码为
IFactory operFactory = new AddFactory();
Operation oper = operFactory.CreateOperation();
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();
工厂方法模式,定义一个用于创建对象的接口让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。 在工厂方法模式中,我们把工厂类抽象出一个接口,这个接口只有一个方法,就是创建抽象产品的工厂方法。然后,所有的要生产具体类的工厂,就去实现这个接口。这样,一个简单工厂模式的工厂类,变成了一个工厂抽象接口和多个具体生成对象的工厂。这时,我们要增加“求M数的N次方”的功能时,就不需要更改原有的工厂类,只需要增加此功能的运算类和相应的工厂类就可以了。
但是,采用工厂方法模式进行事先时,客户端需要决定实例化哪一个工厂类来实现运算类,选择判断的问题还是存在的。也就是说工厂方法把简单工厂的内部逻辑判断移到了客户端代码来进行。你想要增加功能,本来是改工厂类的,而现在是要修改客户端。
抽象工厂模式
提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
IDepartment接口,用于客户端访问,解除与具体数据库访问的耦合。
interface IDepartment {
void Insert(Department department);
Department GetDepartment(int id);
}
SqlserverDepartment类,用于访问SQL Server的Department
class SqlserverDepartment : IDepartment {
public void Insert(Department department) {
Console.WriteLine("在SQL Server中给Department表增加一条记录");
}
public Department GetDepartment(int id) {
Console.WriteLine("在SQL Server中根据ID得到Department表一条记录");
return null;
}
}
AccessDepartment类,用于访问Access的Department
class AccessDepartment : IDepartment {
public void Insert(Department department) {
Console.WriteLine("在Access中给Department表增加一条记录");
}
public Department GetDepartment(int id) {
Console.WriteLine("在Access中根据ID得到Department表一条记录");
return null;
}
}
DataAccess工厂类,融合简单工厂模式。
class DataAccess{
private static readonly String db = "Sqlseerver";
// private static readonly String db = "Access";
public static IUser CreateUser() {
IUser result = null;
switch(db) {
case "Sqlserver":
result = new SqlserverUser();
break;
case "Access":
result = new AccessUser();
break;
}
return result;
}
public static IDepartment CreateDepartment() {
IDepartment result = null;
switch(db) {
case "Sqlserver":
result = new SqlserverDepartment();
break;
case "Access":
result = new AccessDepartment();
break;
}
return result;
}
}
客户端代码
static void Main(String[] args) {
User user = new User();
Deparment dept = new Department();
// 直接得到实际的数据库访问实例,而不存在任何依赖
IUser iu = DataAccess.CreateUser();
iu.Insert(user);
iu.GetUser(1);
// 直接得到实际的数据库访问实例,而不存在任何依赖
IDepartment id = DataAccess.CreateDepartment();
id.Insert(dept);
id.GetDepartment(1);
Console.Read();
}
采用抽象工厂模式,如果我们想要新增一个功能,则需要新实现一个功能类,再在工厂中加入case值。 但这样,还是需要在代码逻辑中修改工厂。其实,我们可以用反射的方式来做,这样,如果需要新增功能,工厂类就不需要变化了。只是,在应用的数据库变化时,修改一下db参数值就可以了。
我们采用反射机制来修改下工厂类
using System.Reflection; // 引入反射
class DataAccess {
private static readonly string AssemblyName = "抽象工厂模式"; // 程序集名称
private static readonly string db = "Sqlserver"; // 数据库名称,可替换成Access
public static IUser CreateUser() {
string className = AssemblyName + "." + db + "User";
return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);
}
public static IDepartment CreateDepartmenet() {
string className = AssemblyName + "." + db + "Department";
return (IDepartment)Assembly.Load(AssembleyName).CreateInstance(className);
}
}
采用反射机制,如果我们要使用oracle数据库,我们只需要增加Oracle的实现类,在将db的值改为Oracle即可。我们也可以将db的值存储到配置文件中,这样,我们不需要修改代码,就可以实现不同数据库间的切换了。
结束语
工厂模式,它隐藏了复杂的执行过程,让客户端只关心执行的结果。各个工厂模式都有他的优缺点,在我们应用时,还是要根据项目的实际情况,进行选择。