抽象工厂模式

说在前面

    上篇文章介绍了简单工厂模式,对类的实例化进行解耦,但它毕竟是简单的工厂模式,使用范围很小,今天就介绍新的工厂模式-抽象工厂模式。

使用场景:

    抽象工厂模式一般用于同一功能(或者说产品吧,想不到更好的说法),比如操作系统,数据库,Redis集群等这些产品都有不同的类型,当我们需要在不同产品间切换时,我们就要去兼容他们的接口,以数据库为例,当你的系统需要同时使用SQLServer,MySQL等数据库时,抽象工厂模式就可以解决,使得系统在数据库切换上解耦,可扩展等待好处,具体下面慢慢说…

抽象工厂模式咋理解?

    对产品的类似接口进行抽象(不同类型接口需要做适配,这里就不多说了),在切换产品时,只要去获取需要的产品接口即可。

示例

    以数据库中的SQLServer,MySQL兼容为例:

 1. 基础实体类及使用类与数据库交互的方法接口:

 public class User
 {
     public int Id { get; set; }
     public string Name { get; set; }
 }

 public interface IUser
 {
     void Insert(User user);
     User GetUser(int id);
 }

 2. 分别用SQLServer和MySQL两个数据来实现实体的Insert和Get接口:

 //SQLServer处理数据的方式
 public class SQLServerUser : IUser
 {
     public User GetUser(int id)
     {
         Console.WriteLine("从SQLServer中获取一条User数据,Id为{0}", id);
         User user = new User
         {
             Id = id,
             Name = ""
         };
         return user;
     }

     public void Insert(User user)
     {
         Console.WriteLine("在SQLServer中增加一条User数据,Id为{0},Name为{1}", user.Id, user.Name);
     }
 }
 //MySQL处理数据的方式
 public class MySQLUser : IUser
 {
     public User GetUser(int id)
     {
         Console.WriteLine("从MySQL中获取一条User数据,Id为{0}", id);
         User user = new User
         {
             Id = id,
             Name = ""
         };
         return user;
     }

     public void Insert(User user)
     {
         Console.WriteLine("在MySQL中增加一条User数据,Id为{0},Name为{1}", user.Id, user.Name);
     }
 }

 3.实现工厂来统一管理这些类的获取,对类进行解耦

 //工厂接口
 public interface IFactory
 {
     IUser CreatUser();
 }
 
 //MySQL 工厂
 public class MySQLFactory : IFactory
 {
     public IUser CreatUser()
     {
         return new MySQLUser();
     }
 }
 
 //SQLServer 工厂
 public class SQLServerFactory : IFactory
 {
     public IUser CreatUser()
     {
         return new SQLServerUser();
     }
 }

 4.基础工作好了,下面看怎么用:

 static void Main(string[] args)
 {
     string db = "SQLServer";
     IFactory factory = null;
     switch (db)
     {
         case "SQLServer":
             factory = new SQLServerFactory();
             break;
         case "MySQL":
             factory = new MySQLFactory();
             break;
         default:
             throw new Exception("暂不兼容其他数据库!");
     }

     IUser user = factory.CreatUser();
     user.Insert(new User
     {
         Id = 1,
         Name = ""
     });
     user.GetUser(1);
  }

 5.这里我们只要去指定数据库,程序就可以按指定数据库执行了,这里的执行的操作数据库操作可以使用简单工厂再次解耦,添加一个管理工厂的工厂中心,如下:

 public static IFactory GetDataDBFactory() {
 	 //可以优化为配置文件,我这里就偷懒不做了
  	 string db = "SQLServer";
	 IFactory factory = null;
	 switch (db)
	 {
	     case "SQLServer":
	         factory = new SQLServerFactory();
	         break;
	     case "MySQL":
	         factory = new MySQLFactory();
	         break;
	     default:
	         throw new Exception("暂不兼容其他数据库!");
	 }
	 return factory;
 }

 再次使用:

 static void Main(string[] args)
 {  
     IFactory factory = DataFactory.GetDataDBFactory();
     IUser user = factory.CreatUser();
     user.Insert(new User
     {
         Id = 1,
         Name = ""
     });
     user.GetUser(1);
 }

 到这里,当我们需要切换数据库,只需要把简单工厂中数据库字段修改掉即可,进一步优化,可以将数据库名称的配置到配置文件中,我们只需要修改配置文件即可切换数据库,这样是不是很nice。

 以上,我们已经把抽象工厂和简单工厂都用上了,程序的确实现了解耦,也遵循了单一职责,开闭原则,数据库切换改配置即可,代码需要改动迭代,只要改对应功能即可。但是呢,
如果我们再添加或修改一个实体类,需要同时在工厂中加上它的方法,代码量很大,且在简单工厂中心需要使用cese语句,这里不符合低耦合标准。怎么解决呢,往下看:

下面我们使用反射技术来解脱工厂的束缚:

 public class DataAcess
 {
     //数据库:可配置在配置文件中
     static string db = "SQLServer";
     //程序集名称
     static string AssemblyName = "SQLFactoryDemo";

     //User类
     public static IUser GetUser()
     {
         //类名称
         string ClassName = "SQLFactoryDemo.Interface." + db + "User";
         IUser user = (IUser)Assembly.Load(AssemblyName).CreateInstance(ClassName);
         return user;
     }
 }

 通过这个反射我们直接获得了类的实体对象,不再需要工厂处理,直观上看代码量少了几乎一半,效果同样达到了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-小龙人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值