zoukankan      html  css  js  c++  java
  • 抽象工厂模式(13)

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

    同样,我们来举一个案例

    一、案例

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

     1     /// <summary>
     2     /// User中的字段
     3     /// </summary>
     4     class User
     5     {
     6         private int _id;
     7 
     8         public int Id
     9         {
    10             get
    11             {
    12                 return _id;
    13             }
    14 
    15             set
    16             {
    17                 _id = value;
    18             }
    19         }
    20 
    21         public string Name
    22         {
    23             get
    24             {
    25                 return _name;
    26             }
    27 
    28             set
    29             {
    30                 _name = value;
    31             }
    32         }
    33 
    34         private string _name;
    35     }
    36     /// <summary>
    37     /// SqlServer类
    38     /// </summary>
    39     class SqlserverUser
    40     {
    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:IUser
    19     {
    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             set
    13             {
    14                 _id = value;
    15             }
    16         }
    17 
    18         public string Name
    19         {
    20             get
    21             {
    22                 return _name;
    23             }
    24 
    25             set
    26             {
    27                 _name = value;
    28             }
    29         }
    30 
    31         private string _name;
    32     }
    33     interface IDepartment
    34     {
    35         void Insert(Department department);
    36         Department GetDepartment(int id);
    37     }
    38 
    39     class SqlServerDepartment:IDepartment
    40     {
    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 : IDepartment
    54     {
    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 : IFactory
    20     {
    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 分支。

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

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

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


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

  • 相关阅读:
    ansible的使用
    Selenium2+python自动化68-html报告乱码问题【转载】
    Selenium2+python自动化67-用例失败自动截图【转载】
    Selenium2+python自动化66-装饰器之运行失败截图【转载】
    Selenium2+python自动化65-js定位几种方法总结【转载】
    selenium+python自动化82-只截某个元素的图【转载】
    selenium+python自动化81-html报告优化(饼图+失败重跑+兼容python2&3)【转载】
    selenium+python自动化79-文件下载(SendKeys)【转载】
    selenium+python自动化77-autoit文件上传【转载】
    Pycharm上python和unittest两种姿势傻傻分不清楚【转载】
  • 原文地址:https://www.cnblogs.com/xiaomowang/p/6346615.html
Copyright © 2011-2022 走看看