抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的类
该模式优缺点: 最大的好处是易于交换产品系列,由于具体工厂类, 在一个应用中只需要初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它需要在改变具体工厂即可使用不同的产品配置。 它让具体的创建实例过程与客户端分离,客户端是通过他们的抽象接口操纵实例,产品的类名被具体的工厂实现分离,不会出现在客户代码中。
(个人建议: 在学习该模式前,请先把工厂方法模式看一下,因为抽象工厂可以说是工厂方法的升级版)
接下来看题:
一个项目所用的数据库原本是Sqlserver的,但是因为客户需要,所以要改成Access的,数据库中有两个表。 User和Department
先声明两个接口 IUser和IDepartment
public class User
{
public int ID { get; set; }
public string Name { get; set; }
}
public class Department
{
public int ID { get; set; }
public string DeptName { get; set; }
}
public interface IDepartment
{
void Insert(Department dept);
Department GetDepartment(int id);
}
public interface IUser
{
void Insert(User user);
User GetUser(int id);
}
public class SqlserverUser :IUser
{
public void Insert(User user)
{
Console.WriteLine("在SQL Server中给User表增加一条记录");
}
public User GetUser(int id)
{
Console.WriteLine("在SQL Server中根据ID 得到User表一条记录");
return null;
}
}
public class AccessUser : IUser
{
public void Insert(User user)
{
Console.WriteLine("在Access中给User表增加一条记录");
}
public User GetUser(int id)
{
Console.WriteLine("在Access中根据ID 得到User表一条记录");
return null;
}
}
public class SqlserverDepartment : IDepartment
{
public void Insert(Department dept)
{
Console.WriteLine("向Sql server数据库中往表Department添加一条数据");
}
public Department GetDepartment(int id)
{
Console.WriteLine("在Sqlserver 中根据ID 得到Department表一条记录");
return null;
}
}
public class AccessDepartment : IDepartment
{
public void Insert(Department dept)
{
Console.WriteLine("向Access数据库中往表Department添加一条数据");
}
public Department GetDepartment(int id)
{
Console.WriteLine("在Access 中根据ID 得到Department表一条记录");
return null;
}
}
在Main方法的调用:
User user = new User();
Department dept = new Department();
IFactory factory = new SqlServerFactory();
IUser suser = factory.CreateUser();
IDepartment sdept = factory.CreateDepartment();
suser.Insert(user);
suser.GetUser(1);
sdept.Insert(dept);
sdept.GetDepartment(1);
结果:
可能我之前写的抽象模式UML图,大家看的不太懂,这也没办法,CSDN上面我能画成这样的图,也可以了。 为了让大家更清晰的看到模式UML图。我从网上找了一个。 思想方面还是一样的。
这里把Creator想象为IFactory , ProductA为IUser ,ProductB为IDepartment. 请大家自觉脑补。 嘿嘿。
这就是抽象工厂模式了,看到这里大家是不是觉得奇怪。(可能有人觉得,这才两个表, 代码就写的这么多了,那要是再多几个表,咋整啊。这模式也太不中用了。 )
别急,接下来,才是重点。
解决抽象工厂模式大量冗余代码的方案是 —— 用反射+抽象工厂来处理
反射的写法:
1. using System.Reflection; 引用命名空间
2. IUser result = (IUser)Assembly.Load(AssemblyName).CreateInstance(命名空间.类名); AssemblyName 是程序集名称
这里的SimpleFactory类,用反射技术已经取代了,IFactory、SqlserverFactory 和AccessFactory
//App.cinfg
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DB" value="Sqlserver"/>
</appSettings>
</configuration>
public class SimpleFactory
{
private static readonly string AssemblyName = "AbstractFP";
private static readonly string db = ConfigurationManager.AppSettings["DB"];
// IUser result = (IUser)Assembly.Load(AssemblyName).CreateInstance("抽象工厂模式.SqlserverUser");
public static IUser CreateUser()
{
//获取本类的程序集名称
string Name = typeof(SimpleFactory).Assembly.GetName().Name;
string className = AssemblyName + "." + db + "User";
return (IUser)Assembly.Load(AssemblyName).CreateInstance(className) ;
}
public static IDepartment CreateDepartment()
{
string className = AssemblyName + "." + db + "Department";
return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(className);
}
}
在Main方法中的:
User u = new User();
IUser sql = SimpleFactory.CreateUser();
sql.Insert(u);
sql.GetUser(1);
Console.ReadLine();
结果:
(欢迎大家来访,如果有不足之处还请指出)