创建型模式:抽象工厂(Abstract Factory)
定义
- 提供一个用于创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。
UML类图
工厂方法模式切换数据库
namespace 抽象工厂02
{
/// <summary>
/// 抽象产品
/// </summary>
public interface IUser
{
User GetUser(int id);
void InsertUser(User entity);
}
}
namespace 抽象工厂02
{
/// <summary>
/// 用户表
/// </summary>
public class User
{
public int ID { get; set; }
public string Name { get; set; }
}
}
using System;
namespace 抽象工厂02
{
/// <summary>
/// 具体产品
/// </summary>
public class SqlServerUser : IUser
{
public User GetUser(int id)
{
Console.WriteLine("在SQL Server中根据ID得到User表中一条记录");
return null;
}
public void InsertUser(User entity)
{
Console.WriteLine("在SQL Server中给User表中增加一条记录");
}
}
}
namespace 抽象工厂02
{
/// <summary>
/// 抽象工厂
/// </summary>
public interface IFactory
{
IUser CreateUser();
}
}
namespace 抽象工厂02
{
/// <summary>
/// SqlServer方式具体工厂
/// </summary>
public class SqlServerFactory : IFactory
{
public IUser CreateUser()
{
return new SqlServerUser();
}
}
}
using System;
namespace 抽象工厂02
{
/// <summary>
/// Access方式访问数据--具体产品
/// </summary>
public class AccessUser : IUser
{
public User GetUser(int id)
{
Console.WriteLine("在Access中根据ID得到User表中一条记录");
return null;
}
public void InsertUser(User entity)
{
Console.WriteLine("在Access中给User表中增加一条记录");
}
}
}
namespace 抽象工厂02
{
/// <summary>
/// Access方式的工厂
/// </summary>
public class AccessFactory : IFactory
{
public IUser CreateUser()
{
return new AccessUser();
}
}
}
using System;
namespace 抽象工厂02
{
/// <summary>
/// 运用工厂方法模式实现(不同数据库的快速切换)
/// </summary>
class Program
{
static void Main(string[] args)
{
//1.创建具体工厂
IFactory factory = new SqlServerFactory(); //如果用Access数据库只需要将SqlServerFactory改为AccessFactory就可以了
//2.根据工厂生产具体
IUser user= factory.CreateUser();
user.InsertUser(new User() { Name="成吉思汗" });
user.GetUser(3);
Console.ReadKey();
}
}
}
抽象工厂切换数据库,新增一个产品部门
namespace 抽象工厂03
{
/// <summary>
/// 部门表
/// </summary>
public class Department
{
public int ID { get; set; }
/// <summary>
/// 部门名称
/// </summary>
public string Name { get; set; }
}
}
namespace 抽象工厂03
{
/// <summary>
/// 部门抽象接口
/// </summary>
public interface IDepartment
{
Department GetDepartment(int id);
void InsertDepartment(Department entity);
}
}
using System;
namespace 抽象工厂03
{
public class AccessDepartment : IDepartment
{
public Department GetDepartment(int id)
{
Console.WriteLine("在Access中根据ID得到Department表中一条记录");
return null;
}
public void InsertDepartment(Department entity)
{
Console.WriteLine("在Access中给Department表中增加一条记录");
}
}
}
namespace 抽象工厂03
{
/// <summary>
/// 抽象工厂 (应该包含所有产品创建的抽象方法)
/// </summary>
public interface IFactory
{
IUser CreateUser();
IDepartment CreateDepartment();
}
}
namespace 抽象工厂03
{
/// <summary>
/// Access方式的工厂(具体工厂创建具有特定实现的产品对象)
/// </summary>
public class AccessFactory : IFactory
{
public IDepartment CreateDepartment()
{
return new AccessDepartment();
}
public IUser CreateUser()
{
return new AccessUser();
}
}
}
using System;
namespace 抽象工厂03
{
/// <summary>
/// SqlServer部门产品
/// </summary>
public class SqlServerDepartment : IDepartment
{
public Department GetDepartment(int id)
{
Console.WriteLine("在SqlServer中根据ID得到Department表中一条记录");
return null;
}
public void InsertDepartment(Department entity)
{
Console.WriteLine("在SqlServer中给Department表中增加一条记录");
}
}
}
namespace 抽象工厂03
{
/// <summary>
/// SqlServer方式具体工厂
/// </summary>
public class SqlServerFactory : IFactory
{
public IDepartment CreateDepartment()
{
return new SqlServerDepartment();
}
public IUser CreateUser()
{
return new SqlServerUser();
}
}
}
using System;
namespace 抽象工厂03
{
/// <summary>
/// 运用抽象工厂模式实现(不同数据库的快速切换)
/// </summary>
class Program
{
static void Main(string[] args)
{
//1.创建具体工厂
IFactory factory = new AccessFactory();
//2.通过工厂生成具体产品
IDepartment department = factory.CreateDepartment();
//3.根据id获取部门
department.GetDepartment(3);
Console.ReadKey();
}
}
}
抽象工厂第二版
- 去掉具体的AccessFactory和SqlServerFactory,增加一个工厂类DataAccess
namespace 抽象工厂04
{
/// <summary>
/// 增加工厂类改造抽象工厂
/// </summary>
public class DataAccess
{
private static readonly string db = "SqlServer";
//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;
default:
break;
}
return result;
}
public static IDepartment CreateDepartment()
{
IDepartment result = null;
switch (db)
{
case "SqlServer":
result = new SqlServerDepartment();
break;
case "Access":
result = new AccessDepartment();
break;
default:
break;
}
return result;
}
}
}
namespace 抽象工厂04
{
/// <summary>
/// 用简单工厂改造抽象工厂
/// </summary>
class Program
{
static void Main(string[] args)
{
IUser user = DataAccess.CreateUser(); //直接得到数据库实例,不存在任何依赖
user.GetUser(3);
IDepartment deparment = DataAccess.CreateDepartment();
deparment.InsertDepartment(new Department() { Name="研发部" });
}
}
}
抽象工厂第三版优化
- 使用反射的方式加配置文件的方式可做到动态切换数据库
- 添加配置文件App.config
using System.Configuration;
using System.Reflection;
namespace 抽象工厂05
{
/// <summary>
/// 通过反射创建对象
/// </summary>
public class DataAccess
{
private static readonly string AssemblyName = "抽象工厂05";
private static readonly string db = ConfigurationManager.AppSettings["db"];
/// <summary>
/// 创建用户抽象产品的工厂方法
/// </summary>
/// <returns></returns>
public static IUser CreateUser()
{
string className= AssemblyName + "." + db + "User";
return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);
}
/// <summary>
/// 创建部门抽象产品的工厂方法
/// </summary>
/// <returns></returns>
public static IDepartment CreateDepartment()
{
string className = AssemblyName + "." + db + "Department";
return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(className);
}
}
}
using System;
namespace 抽象工厂05
{
/// <summary>
/// 反射+抽象工厂方式实现数据访问
/// </summary>
class Program
{
static void Main(string[] args)
{
IUser iUser = DataAccess.CreateUser();
iUser.InsertUser(new User() { Name="赵一曼" });
IDepartment iDepartment = DataAccess.CreateDepartment();
iDepartment.GetDepartment(3);
Console.ReadKey();
}
}
}
优点
- 易于交换产品系列,由于具体工厂类在每一个应用中只需要在初始化的时候出现一次,这就使得改变一个具体应用工厂变得非常容易。只需要改变具体工厂即可改变不同的产品配置。
- 它让具体的创建实例过程与客户端分类,客户端是通过它们的抽象接口操作实例,产品的具体类名也被具体工厂的实现分离。不会出现在客户代码中。
- 很好的遵循了开放-封闭原则。对于新添加产品只需要在工厂方法里面添加新的工厂就可以了。
缺点
- 标准的抽象工厂需要额外增加很多工厂类,但是用简单工厂优化后就相对好很多。
作者:江宁织造
博客:http://www.cnblogs.com/wgx0428/
博客:http://www.cnblogs.com/wgx0428/