【前言】
上篇文章分析学习了一下外观模式的适用情况和经典实例。今天再来看看重构时用到的另一个设计模式——抽象工厂。
抽象工厂的作用主要就是在有一系列工厂且每个工厂都有一系列产品可以选择的时候,把系列产品统一一个接口,并且把具体产品与客户端解耦合。就像我们的系统可以有许多种数据库可选择,我们把可能用到的数据库都写成工厂。 比如我们可能用到sql server 和 Access。
【demo 类图】
【demo 具体实现】
具体工厂与具体产品:
Access factory 类:
using abstrctfactory;
namespace abstrctfactory {
public class AccessFactory : IFactory //实例化AccessUser和AccessDepartment
{
public IDepartment CreateDepartment()
{
return new AccessDepartment();
}
public IUser CreateUser()
{
return new AccessUser();
}
}//end AccessFactory
}//end namespace abstrctfactory
Access User 类:
using abstrctfactory;
using System;
namespace abstrctfactory {
public class AccessUser : IUser {
public void Insert(User user )
{
Console.WriteLine("在SQL server 中给User表增加一条记录");
}
public User GetUser(int id)
{
Console.WriteLine("在SQL server 中根据ID得到 User 表一条记录");
return null;
}
}//end AccessUser
}//end namespace abstrctfactory
using ConsoleApplication4;
using abstrctfactory;
using System;
namespace abstrctfactory {
public class SqlserverDepartment : IDepartment //用简单的控制台程序来说明设计模式。
{
public void Insert(Department department)
{
Console.WriteLine("在SQL Server 中给Department 表增加一条记录"); //具体的实践代码用console.writeline 代替。
}
public Department GetDepartment(int id )
{
Console.WriteLine("在SQL Server中跟据ID得到Department 表一条记录");
return null;
}
public virtual void Dispose(){
}
}//end SqlserverDepartment
}//end namespace abstrctfactory
using abstrctfactory;
namespace abstrctfactory {
public class SqlserverFactory : IFactory {
public IDepartment CreateDepartment()
{
return new SqlserverDepartment(); //返回一个实现接口的对象
}
public IUser CreateUser()
{
return new SqlserverUser(); //返回一个实现接口的对象
}
}//end SqlserverFactory
}//end namespace abstrctfactory
using abstrctfactory;
using System;
namespace abstrctfactory {
public class SqlserverUser : IUser
{
public void Insert (User user)
{
Console.WriteLine ("在SQL server 中给User表增加一条记录");
}
public User GetUser(int id )
{
Console.WriteLine("在SQL Server 中给User 表增加一条记录");
return null;
}
}//end SqlserverUser
}//end namespace abstrctfactory
接口:
namespace abstrctfactory {
public interface IUser // 用于客户端的访问,接触与具体数据库之间的耦合
{
void Insert(User user);
User GetUser(int id);
}//end IUser
}//end namespace abstrctfactory
using System;
namespace abstrctfactory {
public interface IFactory //定义一个创建访问department 对象的工厂接口
{
IDepartment CreateDepartment();
IUser CreateUser();
}//end IFactory
}//end namespace abstrctfactory
namespace abstrctfactory {
public interface IDepartment //设定一个接口:部门要有插入部门和获得部门两个方法
{
void Insert(Department department);
Department GetDepartment(int id);
}//end IDepartment
}//end namespace abstrctfactory
实体类:用来传输数据
<pre name="code" class="csharp">namespace abstrctfactory
{
public class User //user类来传递用户相关信息数据
{
private int _id;
public int ID
{
get { return _id; }
set { ID = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
}
namespace abstrctfactory
{
public class Department //部门类来传递部门信息数据
{
private int _id;//声明一个int变量存放ID
public int ID //ID属性
{
get { return _id; }
set { _id = value; }
}
private string _deptname;//声明一个string变量存放部门名称
public string DeptName//Deptname 属性
{
get { return _deptname; }
set { _deptname = value; }
}
}
}
客户端:
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
User user =new User ();
Department dept =new Department ();
//IFactory factory =new sqlserverFactory(): 换数据库的话只要改这一句话就好了
IFactory factory =new AccessFactory ();
IUser iu =factory.CreateUser() ; //产品以接口的方式出现
iu.Insert(user );
iu.GetUser(1);
IDepartment id = factory.CreateDepartment(); //产品以接口的方式出现
id.Insert(dept);
id.GetDepartment (1);
Console.Read();
}
}
}
【适用情况】
1.我的系统不用知道你的产品如何生产的, 只要能用就行。
2.产品有许多种相似的, 但我只用一个。(数据库有很多 ,但是一个功能块里只是用一种)
3.所有产品以统一接口的出现, 使客户端不依赖具体实现
【优点】
1.它分离了具体的类
2.它使得易于交换产品系列
3.它有利于产品的一致性
【缺点】
难以支持新种类的产品
【总结】
可是即便是使用了抽象工厂, 我们修改数据库的时候还是要打开代码,在客户端中做更改,而且增加新数据库的时候要做好多改动…… 有没有什么方法能把这两个问题解决了呢? 下篇博客继续介绍代码的改进版。