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

    前面我们介绍了简单工厂模式和工厂方法模式,现在简单的回顾一下:

    简单工厂模式是充分利用面向对象的三大特性,将操作要素和操作方法对象化,通过定义工厂方法,决定实例化哪个对象。但简单工厂模式不利于程序的扩展,在需要扩展的时候需要将整个工程类开放,不符合开放-封闭原则。

    在简单工厂模式的基础上,我们通过继承接口实现个操作对象的实例化,各具体操作类各自实现相应的方法,只需实现工厂类接口方法即可,在对功能进行扩展时,不需要对工厂类接口进行修改,只需新增操作类和实例化自己的工厂类即可。

    那我们为什么需要抽象工厂模式呢?

    当我们项目的数据库需要从sqlserver改成oracle时,当初用抽象工厂模式设计的优点就体现出来了。

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

    以数据访问为例:

    1     interface IUser
    2     {
    3         void Insert(User user);
    4 
    5         User GetUser(int id);
    6     }
     1     class SqlserverUser : IUser
     2     {
     3         public void Insert(User user)
     4         {
     5             Console.WriteLine("在Sqlserver中给User表增加一条记录");
     6         }
     7 
     8         public User GetUser(int id)
     9         {
    10             Console.WriteLine("在Sqlserver中根据ID得到User表一条记录");
    11             return null;
    12         }
    13     }
    14 
    15     class AccessUser : IUser
    16     {
    17         public void Insert(User user)
    18         {
    19             Console.WriteLine("在Access中给User表增加一条记录");
    20         }
    21 
    22         public User GetUser(int id)
    23         {
    24             Console.WriteLine("在Access中根据ID得到User表一条记录");
    25             return null;
    26         }
    27     }
     1     interface IFactory
     2     {
     3         IUser CreateUser();
     4     }
     5 
     6     class SqlServerFactory : IFactory
     7     {
     8         public IUser CreateUser()
     9         {
    10             return new SqlserverUser();
    11         }
    12     }
    13 
    14     class AccessFactory : IFactory
    15     {
    16         public IUser CreateUser()
    17         {
    18             return new AccessUser();
    19         }
    20     }

    客户端调用:

     1             User user = new User();
           //IFactory factory=new SqlServerFactory();//SqlServer调用 3 IFactory factory = new AccessFactory();//Access调用 4 5 IUser iu = factory.CreateUser(); 6 7 iu.Insert(user); 8 iu.GetUser(1); 9 10 Console.Read();

    当我们新增了一个表时,我们至少要新增四个类:表对象类,表对应接口类,表对象操作在sqlserver类,表对象操作在access类;修改三个类:工厂接口类,工厂接口类在sqlserver中实现类,工厂接口类在access中实现类。

    还有就是当我们更改数据库时,程序中所有对工厂类进行实例化的地方都要修改。为此,我们可以通过简单工厂来改进抽象工厂:

    将工厂接口类,工厂接口类在sqlserver中实现类,工厂接口类在access中实现类融合到一个类,也就是说将数据访问判断从客户端移到统一类:

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

    但现在又有新的问题:当我们需要增加oracle数据访问时,需要在dataaccess类中的每个方法新增switch。

    为了解决这个问题,我们需要用到反射机制。

    使用.net里面的system.Reflection实现反射:

     1     class DataAccess
     2     {
     3         private static readonly string AssemblyName = "抽象工厂模式";//命名空间
     4         private static readonly string db = "Sqlserver";//要实例化的类前缀
     5         //private static readonly string db = "Access";
     6 
     7         public static IUser CreateUser()
     8         {
     9             string className = AssemblyName + "." + db + "User";
    10             return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);
    11         }
    12 
    13         public static IDepartment CreateDepartment()
    14         {
    15             string className = AssemblyName + "." + db + "Department";
    16             return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(className);
    17         }
    18     }

    当然为了在更换数据库时完全不修改程序,我们可以用配置文件代替,在程序中读取配置文件。

    private static readonly string db = "Sqlserver";//要实例化的类前缀

    这样我们就可以在不修改DataAccess类的情况下更换数据库。

    寻找突破。。。
  • 相关阅读:
    iptables服务器主机防火墙
    VMware克隆Linux虚拟机报错
    CentOS7.3下yum安装MariaDB10.3.12并指定utf8字符集
    CentOS7.3yum安装MariaDB报错[Errno 256]
    [LeetCode] 121. Best Time to Buy and Sell Stock
    [LeetCode] 116. Populating Next Right Pointers in Each Node
    [LeetCode] 113. Path Sum II
    jQuery实现图片添加及预览
    H5移动端适配——解决移动端必须手动调整以适配的问题
    [LeetCode] 110. Balanced Binary Tree
  • 原文地址:https://www.cnblogs.com/iskyoole/p/2552732.html
Copyright © 2011-2022 走看看