抽象工厂模式(13)

来源:互联网 发布:excel表格数据透视表 编辑:程序博客网 时间:2024/06/03 21:40

今天呢,给大家来讲一下抽象工厂模式,说到这里,大家会想到好多种关于工厂的模式,前面已经讲了两种了 简单工厂模式和工厂方法模式。好,下面我们来看一下抽象工厂模式。

同样,我们来举一个案例

一、案例

我们在做项目的时候,肯定会与数据库打交道,那么我们用简单的控制台应用程序来模拟一个向SqlServer数据库表中插入和读取的情况。

 1     /// <summary> 2     /// User中的字段 3     /// </summary> 4     class User 5     { 6         private int _id; 7  8         public int Id 9         {10             get11             {12                 return _id;13             }14 15             set16             {17                 _id = value;18             }19         }20 21         public string Name22         {23             get24             {25                 return _name;26             }27 28             set29             {30                 _name = value;31             }32         }33 34         private string _name;35     }36     /// <summary>37     /// SqlServer类38     /// </summary>39     class SqlserverUser40     {41         public void Insert(User user)42         {43             Console.WriteLine("在Sql server 中 给User 表增加一条记录");44         }45 46         public User GetUser(int id)47         {48             Console.WriteLine($"在Sql server 中根据ID获取User表中的一条记录");49             return null;50         }51     }

客户端调用:

 1     internal class Program 2     { 3         public static void Main() 4         { 5             User user = new User(); 6             SqlserverUser su = new SqlserverUser(); 7             su.Insert(user); 8             su.GetUser(1); 9             Console.ReadKey();10         }

二、演绎

1、第一步演绎

那么问题来了,如果我这个项目数据库换成Oracle,那么我岂不是都要改了,如果想实现自由的切换数据库,我们想到了一个不错的模式,对,工厂方法模式。

让他们都依赖于抽象,所以我们在这里增加两个接口

 1     interface IUser 2     { 3         void Insert(User user); 4         User GetUser(int id); 5     } 6  7     interface IFactory 8     { 9         IUser CraeteUser();10     }

让User 和 SqlServer 等类继承相应的接口

 1     /// <summary> 2     /// SqlServer类 3     /// </summary> 4     class SqlserverUser :IUser 5     { 6         public void Insert(User user) 7         { 8             Console.WriteLine("在Sql server 中 给User 表增加一条记录"); 9         }10 11         public User GetUser(int id)12         {13             Console.WriteLine($"在Sql server 中根据ID获取User表中的一条记录");14             return null;15         }16     }17 18     class OracleUser:IUser19     {20         public void Insert(User user)21         {22             Console.WriteLine("在Oracle 中 给User 表增加一条记录");23         }24 25         public User GetUser(int id)26         {27             Console.WriteLine($"在Oracle 中根据ID获取User表中的一条记录");28             return null;29         }30     }
 1     class SqlServerFactory:IFactory 2     { 3         public IUser CraeteUser() 4         { 5             return new SqlserverUser(); 6         } 7     } 8     class OracleFactory : IFactory 9     {10         public IUser CraeteUser()11         {12             return new OracleUser();13         }14     }

客户端

1         public static void Main()2         {3             User user = new User();4             IFactory factory = new SqlServerFactory();5             IUser su = factory.CraeteUser();6             su.Insert(user);7             su.GetUser(1);8             Console.ReadKey();9         }

以上,我们将案例用工厂方法模式写出来了。

2、第二步演绎

我们的数据库中,不可能之后User表,还有很多其他的表,这样就会产生好多的类哦。

下面,我们在增加一个表(Department)

那么,按照上面的模式就会产生一下面的一坨代码

 1     class Department 2     { 3         private int _id; 4  5         public int Id 6         { 7             get 8             { 9                 return _id;10             }11 12             set13             {14                 _id = value;15             }16         }17 18         public string Name19         {20             get21             {22                 return _name;23             }24 25             set26             {27                 _name = value;28             }29         }30 31         private string _name;32     }33     interface IDepartment34     {35         void Insert(Department department);36         Department GetDepartment(int id);37     }38 39     class SqlServerDepartment:IDepartment40     {41         public void Insert(Department department)42         {43             Console.WriteLine("在SqlServer 中 给Department 表增加一条记录");44         }45 46         public Department GetDepartment(int id)47         {48             Console.WriteLine("在SqlServer 中 根据ID 获取Department 表一条记录");49             return null;50         }51     }52 53     class OracleDepartment : IDepartment54     {55         public void Insert(Department department)56         {57             Console.WriteLine("在Oracle 中 给Department 表增加一条记录");58         }59 60         public Department GetDepartment(int id)61         {62             Console.WriteLine("在Oracle 中 根据ID 获取Department 表一条记录");63             return null;64         }65     }

工厂接口与实现中也新增了方法

 1     interface IFactory 2     { 3         IUser CraeteUser(); 4         IDepartment CreateDepartment(); 5     } 6  7     class SqlServerFactory:IFactory 8     { 9         public IUser CraeteUser()10         {11             return new SqlserverUser();12         }13 14         public IDepartment CreateDepartment()15         {16             return new SqlServerDepartment();17         }18     }19     class OracleFactory : IFactory20     {21         public IUser CraeteUser()22         {23             return new OracleUser();24         }25 26         public IDepartment CreateDepartment()27         {28             return new OracleDepartment();29         }30     }

经过我们这么一步一步的演化,我们重构出了一个非常重要的设计模式,抽象工厂模式。小伙伴们会说,刚刚这不是工厂方法模式吗。

只有一个User表的时候,是只需要工厂方法模式的,但是我们数据库中显然有非常多的表,还SqlServer 和Oracle 这两大分支,所以涉及到解决多种产品分支的问题,有一个专门的工厂模式,叫抽象工厂模式。

什么叫抽象工厂模式呢?提供一系列相关或相互依赖的接口,而无需指定他们具体的类。

这就是抽象工厂模式,他的优缺点很明显。

优点:灵活,产品系列零活切换。

缺点:如果我们再增加一个表,需要改动的地方太多了,需要增加三个类,需要修改三个类,靠,太麻烦了吧。

客户端每一次使用时,需要new 一下,如果客户端有好多处调用的,那么就需要new 好多次。  这些都是他的缺点。

编程是一门艺术,这样大批量的改动,显然是非常丑陋的做法。

我们这里有一个改进的方法,就是用简单工厂方法改进抽象工厂模式。

我们新增加一个类

 1     class DataAccess 2     { 3         private static readonly string db = "SqlServer"; 4         // private static readonly string db = "Oracle"; 5         public static IUser CreateUser() 6         { 7             IUser result = null; 8             switch (db) 9             {10                 case "SqlServer":11                     result = new SqlserverUser();12                     break;13                 case "Oracle":14                     result = new OracleUser();15                     break;16             }17             return result;18         }19 20         public static IDepartment CreateDepartment()21         {22             IDepartment result = null;23             switch (db)24             {25                 case "SqlServer":26                     result = new SqlServerDepartment();27                     break;28                 case "Oracle":29                     result = new OracleDepartment();30                     break;31             }32             return result;33         }34     }

嗯,这样,客户端调用的时候就好调用了。

 1         public static void Main() 2         { 3             User user = new User(); 4             Department dept = new Department(); 5             IUser iu = DataAccess.CreateUser(); 6             iu.Insert(user); 7             iu.GetUser(1); 8             IDepartment d = DataAccess.CreateDepartment(); 9             d.Insert(dept);10             d.GetDepartment(1);11             Console.ReadKey();12         }

ok,那么如果我还想增加一个数据库类型的分支,比如Access数据库,那么需要在DataAccess类的方法中增加一个case 分支。

之前我们也曾提到过相关的问题,就是用 反射 来解决,但一直没有展开来讲,那么下篇博文,我们来给大家讲一讲如何用反射的技术来解决这些问题。

反射反射,程序员的快乐~

好了,今天我们先讲到这里,下一篇我们将用反射技术来解决相关的问题~


本系列将持续更新,喜欢的小伙伴可以点一下关注和推荐,谢谢大家的支持。

0 0