抽象工厂模式

书中引例:项目用的数据库为 SQL Server 。后又需求换成 Access 。数据库都有读写查等共同的操作,


using UnityEngine;
using System.Collections;

public class AbstractFactoryStudy : MonoBehaviour {

	// Use this for initialization
	void Start () {
	    User user = new User();
//        IFactory07 factory07 = new SqlSercerFactory(); 若要换数据库 这两句换一下就行了
        IFactory07 factory07 = new AccessFactory();
	    IUser iu = factory07.CreatUser();
        iu.Insert(user);
	    iu.GetUser(1);
	}
	

}
//IUser 接口 ,用于客户端访问,解除与具体数据库访问的耦合。
public interface IUser
{
    void Insert(User user);
    User GetUser(int id);
}

//SqlsercerUser 用于访问SqlServer的User
public class SqlsercerUser : IUser
{
    public void Insert(User user)
    {
        Debug.Log("在SQL中添加记录");
    }

    public User GetUser(int id)
    {
        Debug.Log("在SQL中获得记录");
        return null;
    }
}
//AccesssUser 用于访问Access的User
public class AccesssUser : IUser {
    public void Insert(User user) {
        Debug.Log("在AccesssUser中添加记录");
    }

    public User GetUser(int id) {
        Debug.Log("在AccesssUser中获得记录");
        return null;
    }
}
//IFactory07 接口, 定义一个创建访问User表对象的抽象的工厂接口。 
public interface IFactory07
{
    IUser CreatUser();
}
//SqlSercerFactory 类,实现 IFactory07 接口,实例化 SqlsercerUser
public class SqlSercerFactory :IFactory07
{
    public IUser CreatUser()
    {
        return  new SqlsercerUser();
    }
}
//AccessFactory 类,实现 IFactory07 接口,实例化 AccessUser
public class AccessFactory : IFactory07 {
    public IUser CreatUser() {
        return new AccesssUser();
    }
}
//User 表结构
public class User
{
    public int ID { get; set; }
    public string name { get; set; }
}

以上想想要换数据库只需要改一句就行了,由于多肽的关系,使得声明的 IUSer 接口的对象 iu 事先根本不知道是在访问那个数据库,却可以在运行时很好的完成工作,实现了业务逻辑与数据访问的解耦。


需要加一个数据库表 Department:

using UnityEngine;
using System.Collections;

public class AbstractFactoryStudy : MonoBehaviour {
	// Use this for initialization
	void Start () {
	    User user = new User();
//        IFactory07 factory07 = new SqlSercerFactory(); 若要换数据库 这两句换一下就行了
        IFactory07 factory07 = new AccessFactory();
	    
        IUser iu = factory07.CreatUser();
        iu.Insert(user);
	    iu.GetUser(1);
        Department dept = new Department();
	    IDepartment id = factory07.CreatDepartment();
        id.Insert(dept);
        id.GetDepartment(1);
	}
	

}

public interface IDepartment
{
    void Insert(Department department);
    Department GetDepartment(int id );
}

public interface IUser
{
    void Insert(User user);
    User GetUser(int id);
}
public class SqlsercerDepartment : IDepartment {
    public void Insert(Department department)
    {
        Debug.Log("在SQL中添加记录");
    }
    public Department GetDepartment(int id)
    {
        Debug.Log("在SQL中获得记录");
        return null;
    }
}
public class AccesssDepartment : IDepartment {
    public void Insert(Department department) {
        Debug.Log("在SQL中添加记录");
    }
    public Department GetDepartment(int id) {
        Debug.Log("在SQL中获得记录");
        return null;
    }
}
public class SqlsercerUser : IUser
{
    public void Insert(User user)
    {
        Debug.Log("在SQL中添加记录");
    }

    public User GetUser(int id)
    {
        Debug.Log("在SQL中获得记录");
        return null;
    }
}
public class AccesssUser : IUser {
    public void Insert(User user) {
        Debug.Log("在AccesssUser中添加记录");
    }

    public User GetUser(int id) {
        Debug.Log("在AccesssUser中获得记录");
        return null;
    }
}
public interface IFactory07
{
    IUser CreatUser();
    IDepartment CreatDepartment();// 增加接口的方法
}
public class SqlSercerFactory :IFactory07
{
    public IUser CreatUser()
    {
        return  new SqlsercerUser();
    }
    public IDepartment CreatDepartment()//增加了 SqlsercerDepartment 工厂
    {
        return new SqlsercerDepartment();
    }
}
public class AccessFactory : IFactory07 {
    public IUser CreatUser() {
        return new AccesssUser();
    }
    public IDepartment CreatDepartment()//增加了 AccesssDepartment 工厂
    {
        return new AccesssDepartment();
    }
}

public class User
{
    public int ID { get; set; }
    public string name { get; set; }
}
//Department 表结构
public class Department {
    public int ID { get; set; }
    public string name { get; set; }
}


抽象工厂模式:提供一个创建一系列相关或互相依赖对象的接口, 而无需指定他们具体的类。



AbstractProductA 和 AbstractProductB 是两个抽象产品,之所以为抽象,是因为它们都有可能有两种不同的实现,就刚才的例子来说就是User 和 Department ,而 ProductA1 ProductA2 和 ProductB1  ProductB2 就是对两个抽象产品的具体分类的实现,比如ProductA1可以理解为是 SqlServerUser ,而 ProductB1 是 AccessUser。

IFactory 是一个抽象工厂接口, 它里面应该包含所有的产品创建的抽象方法。而 ConcreteFactory1 和 ConcreteFactory2 就是具体的工厂了,就像 SqlserverFactory 和 AccessFactory 一样。 通常是子啊运行时刻在创建一个ConcreteFactory 类的实例,这个具体的工厂再创建具有特定实现的产品对象,也就是说,为创建不同的产品对象,客户端应使用不同的具体工厂。

优点:易于交换产品系列,由于具体工厂类,在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。 它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户端代码中。

缺点:如果现在又需要加入表 Project 的话,那么至少要增加三个类:IProject  SqlserverProject  AccessProject   还需要更改 IFactory  SqlserverFactory  和  AccessFactory 才可以完全实现。

客户端类并不只有一个,也就是调用IUser 或 IDepartment ,的地方都需要声明 IFactory factory = new AccessFactory(),要换数据库的话 每个地方都要改,所以 可以用简单工厂来改进抽象工厂, 去除 IFactory  SqlserverFactory  和 AccessFactory 三个工厂类。 取而代之的是 DataAccess 类, 用一个简单工厂模式来实现。


using UnityEngine;
public class AbstractFactoryStudy : MonoBehaviour {
	// Use this for initialization
	void Start () {
	    User user = new User();
        Department dept = new Department();
	    //直接得到实际的数据库访问实例,而不存在任何依赖。
        IUser iu = DataAccess.CreateUser();

        iu.Insert(user);
	    iu.GetUser(1);

	    //直接得到实际数据库访问实例,而不存在任何依赖
        IDepartment id = DataAccess.CreateDepartment();
        id.Insert(dept);
	    id.GetDepartment(1);
	}
}

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 SqlsercerUser();
                break;
            case "Access":
                result = new AccesssUser();
                break;
        }
        return result;
    }

    public static IDepartment CreateDepartment()
    {
        IDepartment result = null;
        switch (db)
        {
            case "Sqlserver":
                result = new SqlsercerDepartment();
                break;
            case "Access":
                result = new AccesssDepartment();
                break;
        }
        return result;
    }

}

public interface IDepartment
{
    void Insert(Department department);
    Department GetDepartment(int id );
}

public interface IUser
{
    void Insert(User user);
    User GetUser(int id);
}
public class SqlsercerDepartment : IDepartment {
    public void Insert(Department department)
    {
        Debug.Log("在SQL中添加记录");
    }
    public Department GetDepartment(int id)
    {
        Debug.Log("在SQL中获得记录");
        return null;
    }
}
public class AccesssDepartment : IDepartment {
    public void Insert(Department department) {
        Debug.Log("在SQL中添加记录");
    }
    public Department GetDepartment(int id) {
        Debug.Log("在SQL中获得记录");
        return null;
    }
}
public class SqlsercerUser : IUser
{
    public void Insert(User user)
    {
        Debug.Log("在SQL中添加记录");
    }

    public User GetUser(int id)
    {
        Debug.Log("在SQL中获得记录");
        return null;
    }
}
public class AccesssUser : IUser {
    public void Insert(User user) {
        Debug.Log("在AccesssUser中添加记录");
    }

    public User GetUser(int id) {
        Debug.Log("在AccesssUser中获得记录");
        return null;
    }
}
public class User {
    public int ID { get; set; }
    public string name { get; set; }
}
//Department 表结构
public class Department {
    public int ID { get; set; }
    public string name { get; set; }
}

上述代码抛弃了 IFactory  SqlserverFactory  和 AccessFactory  三个工厂类,取而代之的是 DataAccess类,由于事先设置了db的值(Sqlserver 或 Access),所以简单工厂的方法都不需要传入参数,客户端没有出现任何一个 SQLServer 或 Access 的字样,达到了解耦的目的。

如果再需要加入Oracle数据库的访问的话 需要在DataAccess 类中每个方法的switch 中加case 也比较繁琐,可以利用反射来改进:

Assembly.Load("程序集名称").CreatInstance("命名空间.类名称")

反射引用的命名空间: using System.Reflection;


备注: ReadOnly与Const区别

using UnityEngine;
using System.Reflection;
public class AbstractFactoryStudy : MonoBehaviour {
	void Start () {
	    User user = new User();
        Department dept = new Department();
        IUser iu = DataAccess.CreateUser();

        iu.Insert(user);
	    iu.GetUser(1);
        IDepartment id = DataAccess.CreateDepartment();
        id.Insert(dept);
	    id.GetDepartment(1);
	}
}

public class DataAccess
{
    private static readonly string AssemblyName = "DaHuaSheJi";
    private static readonly string db = "Sqlserver";//可换成 Access。 变化时 之变化这一句就可以了
    public static IUser CreateUser()
    {
        string className = AssemblyName + "." + db + "User";
        return (IUser) Assembly.Load(AssemblyName).CreateInstance(className);/* Unity 中这样写  Type t = Type.GetType("SqlsercerUser");        return (IUser) Activator.CreateInstance(t);*/    }

    public static IDepartment CreateDepartment()
    {
        IDepartment result = null;
        switch (db)
        {
            case "Sqlserver":
                result = new SqlsercerDepartment();
                break;
            case "Access":
                result = new AccesssDepartment();
                break;
        }
        return result;
    }

}

public interface IDepartment
{
    void Insert(Department department);
    Department GetDepartment(int id );
}

public interface IUser
{
    void Insert(User user);
    User GetUser(int id);
}
public class SqlsercerDepartment : IDepartment {
    public void Insert(Department department)
    {
        Debug.Log("在SQL中添加记录");
    }
    public Department GetDepartment(int id)
    {
        Debug.Log("在SQL中获得记录");
        return null;
    }
}
public class AccesssDepartment : IDepartment {
    public void Insert(Department department) {
        Debug.Log("在SQL中添加记录");
    }
    public Department GetDepartment(int id) {
        Debug.Log("在SQL中获得记录");
        return null;
    }
}
public class SqlsercerUser : IUser
{
    public void Insert(User user)
    {
        Debug.Log("在SQL中添加记录");
    }

    public User GetUser(int id)
    {
        Debug.Log("在SQL中获得记录");
        return null;
    }
}
public class AccesssUser : IUser {
    public void Insert(User user) {
        Debug.Log("在AccesssUser中添加记录");
    }

    public User GetUser(int id) {
        Debug.Log("在AccesssUser中获得记录");
        return null;
    }
}
public class User {
    public int ID { get; set; }
    public string name { get; set; }
}
//Department 表结构
public class Department {
    public int ID { get; set; }
    public string name { get; set; }
}

以上 ,如果在需要增加 Project 产品时,只需要增加三个与 Project 相关的类,在修改 DataAccess ,在其中增加一个 public static IProject CreatProject() 方法就可以了。


在追求完美一下, 就是将要读的数据库名称字符串放到配置文件中,添加一个 App.config文件,内容下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <addSettings>
      <add key="DB" value="Sqlserver"/>
  </addSettings>
</configuration>


在程序中去读取这个value值就可以了。

所有的简单工厂都可以考虑用反射技术来去除 switch 或 if 解除分支判断带来的耦合。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值