抽象工厂(Abstract Factory)
抽象工厂,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。别名
Kit
结构
参与者
AbstractFactory——声明一个创建抽象产品对象的操作接口。
ConcreteFactory
——实现创建具体产品对象的操作。
AbstractProduct
——为一类产品对象声明一个接口。
ConcreteProduct
——定义一个将被相应的具体工厂创建的产品对象。
——实现AbstractProduct接口。
Client
——仅使用由AbstractFactory和AbstractProduct类声明的接口。
效果
1)它分离了具体的类 Abstract Factory 模式帮助你控制一个应用创建的对象的类。因为一个工厂封装创建产品对象的责任和过程,它将客户与类的实现分离。客户通过它们的抽象接口操纵实例。产品的类名也在具体工厂的实现中被分离;它们不出现在客户代码中。
2)它使得易于交换产品系列 在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。
3)它有利于产品的一致性。
4)难以支持新种类的产品。
实现
1)将工厂作为单件。
2)创建产品 最通常的一个办法是为每一个产品定义一个工厂方法(Factory Method),一个具体的工厂将为每个产品重定义该工厂方法以指定产品。虽然这样的实现很简单,但它却要求每个产品系列都要有一个新的具体工厂子类,即使这些产品系列的差别很小。如果有多个可能的产品系列,具体工厂也可以使用Prototype模式来实现。具体工厂使用产品系列中每一个产品的原型实例来初始化,且它通过复制它的原型来创建新的产品。在基于原型的方法中,使得不是每个新的产品系列都需要一个新的具体工厂类。
3)定义可扩展的工厂 AbstractFactory通常为每一种它可以生产的产品定义一个操作。产品的种类被编码在操作型构中。增加一种新的产品要求改变AbstractFactory的接口以及所有与它相关的类。一个更灵活但不太安全的设计是给创建对象的操作增加一个参数。该参数指定了将被创建的对象的种类。它可以是一个类标识符、一个整数、一个字符串,或其他任何可以标识这种产品的东西。
工厂方法
在抽象工厂中使用工厂方法
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyAbstractFactory
{
public interface IFactory
{
IUser CreateeUser();
IDepartment CreateDepartment();
}
public class SqlserverFactory : IFactory
{
public IUser CreateeUser()
{
return new SqlserverUser();
}
public IDepartment CreateDepartment()
{
return new SqlserverDepartment();
}
}
public class AccessFactory : IFactory
{
public IUser CreateeUser()
{
return new AccessUser();
}
public IDepartment CreateDepartment()
{
return new AccessDepartment();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyAbstractFactory
{
public interface IUser
{
void Insert(string user);
string GetUser(int id);
}
public class SqlserverUser : IUser
{
public void Insert(string user)
{
Console.WriteLine("在SQL server中给User表增加一条记录");
}
public string GetUser(int id)
{
Console.WriteLine("在SQL server中根据ID得到User表一条记录");
return null;
}
}
public class AccessUser : IUser
{
public void Insert(string user)
{
Console.WriteLine("在Access中给User表增加一条记录");
}
public string GetUser(int id)
{
Console.WriteLine("在Access中根据ID得到User表一条记录");
return null;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyAbstractFactory
{
public interface IDepartment
{
void Insert(string dapartment);
string GetDepartment(int id);
}
public class SqlserverDepartment : IDepartment
{
public void Insert(string dapartment)
{
Console.WriteLine("在SQL server中给Department表增加一条记录");
}
public string GetDepartment(int id)
{
Console.WriteLine("在SQL server中根据ID得到Department表一条记录");
return null;
}
}
public class AccessDepartment : IDepartment
{
public void Insert(string dapartment)
{
Console.WriteLine("在Access中给Department表增加一条记录");
}
public string GetDepartment(int id)
{
Console.WriteLine("在Access中根据ID得到Department表一条记录");
return null;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyAbstractFactory
{
class Program
{
static void Main(string[] args)
{
string user = "user";
string dept = "Department";
IFactory factory = new AccessFactory(); // 实例化工厂
IUser iu = factory.CreateeUser(); // 实例化产品
iu.Insert(user);
iu.GetUser(1);
IDepartment id = factory.CreateDepartment(); // 实例化产品
id.Insert(dept);
id.GetDepartment(1);
Console.ReadKey();
}
}
}
(C#)
在使用简单工厂的地方,可以考虑用
反射技术
来去除switch或if,解除分支判断带来的耦
合。
抽象工厂(配置文件)+反射
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Configuration;
namespace MyAbstractFactory2
{
// 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;
// }
// 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;
// }
// }
class DataAccess // 利用反射
{
private static readonly string assemblyName = "MyAbstractFactory2";
// private static readonly string db = "Sqlserver";
// 可以放到配置文件中
private static readonly string db = ConfigurationManager.AppSettings["DB"];
public static IUser CreateUser()
{
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);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyAbstractFactory2
{
public interface IUser
{
void Insert(string user);
string GetUser(int id);
}
public class SqlserverUser : IUser
{
public void Insert(string user)
{
Console.WriteLine("在SQL server中给User表增加一条记录");
}
public string GetUser(int id)
{
Console.WriteLine("在SQL server中根据ID得到User表一条记录");
return null;
}
}
public class AccessUser : IUser
{
public void Insert(string user)
{
Console.WriteLine("在Access中给User表增加一条记录");
}
public string GetUser(int id)
{
Console.WriteLine("在Access中根据ID得到User表一条记录");
return null;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyAbstractFactory2
{
public interface IDepartment
{
void Insert(string dapartment);
string GetDepartment(int id);
}
public class SqlserverDepartment : IDepartment
{
public void Insert(string dapartment)
{
Console.WriteLine("在SQL server中给Department表增加一条记录");
}
public string GetDepartment(int id)
{
Console.WriteLine("在SQL server中根据ID得到Department表一条记录");
return null;
}
}
public class AccessDepartment : IDepartment
{
public void Insert(string dapartment)
{
Console.WriteLine("在Access中给Department表增加一条记录");
}
public string GetDepartment(int id)
{
Console.WriteLine("在Access中根据ID得到Department表一条记录");
return null;
}
}
}
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DB" value="Sqlserver"/>
</appSettings>
</configuration>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyAbstractFactory2
{
class Program
{
static void Main(string[] args)
{
string user = "user";
string dept = "Department";
IUser iu = DataAccess.CreateUser(); // 简单工厂
iu.Insert(user);
iu.GetUser(1);
IDepartment id = DataAccess.CreateDepartment();
id.Insert(dept);
id.GetDepartment(1);
Console.ReadKey();
}
}
}