zoukankan      html  css  js  c++  java
  • C#基础--抽象工厂

    开发需求:

    同一套系统,需要根据客户需求采用不同的数据库。

    一般实现:

    开发多套系统,每套系统对应一个数据库。

    缺点:

    需要同时维护多套系统,难度大。

    解决:

    使用抽象工厂模式,同一套系统里面开发多个数据库的DAL,根据客户需求来确定使用哪个数据库。

    抽象工厂设计模式

    基于抽象工厂模式设计DAL方案

    项目各层之间的引用

    代码示例

    根据以上,建立各层,各层引用参考上面:

    从底层开始构建代码:

    编写不同数据库的DAL,我这里仅仅是文件夹形式将Access、SQLServer数据DAL模块分类,实际开发可以使用dll等分层。

    仅做了查询Service

    IDAL接口定义

    DAL需要基于接口开发,所以先定义接口,我们这里仅使用到了两个接口:

    using Models;
    
    namespace IDAL
    {
        public interface IClassService
        {
            List<StudentClass> GetAllClasses();
        }
    }
    
    
    namespace IDAL
    {
        public interface IStudentService
        {
            List<Student> GetStudentsByClassId(int classId);
        }
    }

    基于接口开发DAL:

    Access数据库

    AccessHelper:

     1 using System.Data;
     2 using System.Data.OleDb;
     3 using System.Configuration;
     4 
     5 namespace DAL.Access
     6 {
     7     class AccessHelper
     8     {
     9         private static readonly string connString = ConfigurationManager.ConnectionStrings["AccessConnString"].ToString();
    10         public static OleDbDataReader GetReader(string sql)
    11         {
    12             OleDbConnection conn = new OleDbConnection(connString);
    13             OleDbCommand cmd = new OleDbCommand(sql, conn);
    14             try
    15             {
    16                 conn.Open();
    17                 return cmd.ExecuteReader(CommandBehavior.CloseConnection);
    18             }
    19             catch (OleDbException ex)
    20             {
    21                 if (conn.State == ConnectionState.Open)
    22                     conn.Close();
    23                 throw new Exception("应用程序与数据库连接异常:" + ex.Message);
    24             }
    25             catch (Exception ex)
    26             {
    27                 if (conn.State == ConnectionState.Open)
    28                     conn.Close();
    29                 throw ex;
    30             }
    31         }
    32     }
    33 }
    View Code

    ClassService:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using IDAL;
     7 using Models;
     8 using System.Data;
     9 using System.Data.OleDb;
    10 
    11 namespace DAL.Access
    12 {
    13     class ClassService : IClassService
    14     {
    15         public List<StudentClass> GetAllClasses()
    16         {
    17             string sql = "select * from StudentClass";
    18             OleDbDataReader objReader = AccessHelper.GetReader(sql);
    19             List<StudentClass> objStuClass = new List<StudentClass>();
    20             while (objReader.Read())
    21             {
    22                 objStuClass.Add(new StudentClass
    23                 {
    24                     ClassId = Convert.ToInt32(objReader["ClassId"]),
    25                     ClassName = objReader["ClassName"].ToString()
    26                 });
    27             }
    28             objReader.Close();
    29             return objStuClass;
    30         }
    31     }
    32 }
    View Code

    StudentService:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using IDAL;
     7 using System.Data;
     8 using System.Data.OleDb;
     9 using Models;
    10 
    11 namespace DAL.Access
    12 {
    13     public class StudentService : IStudentService
    14     {
    15         public List<Student> GetStudentsByClassId(int classId)
    16         {
    17             StringBuilder sqlBuilder = new StringBuilder("select StudentId,StudentName,Gender,StudentIdNo,Birthday,PhoneNumber,ClassName,Students.ClassId from Students ");
    18             sqlBuilder.Append("inner join StudentClass on StudentClass.ClassId=Students.ClassId ");
    19             if (classId > 0)
    20                 sqlBuilder.Append($"where Students.ClassId={classId} ");
    21             List<Student> stuList = new List<Student>();
    22             OleDbDataReader objReader = null;
    23             try
    24             {
    25                 objReader = AccessHelper.GetReader(sqlBuilder.ToString());
    26                 while (objReader.Read())
    27                 {
    28                     stuList.Add(new Student
    29                     {
    30                         StudentId = Convert.ToInt32(objReader["StudentId"]),
    31                         StudentName = objReader["StudentName"].ToString(),
    32                         Gender = objReader["Gender"].ToString(),
    33                         StudentIdNo = objReader["StudentIdNo"].ToString(),
    34                         Birthday = Convert.ToDateTime(objReader["Birthday"]),
    35                         PhoneNumber = objReader["PhoneNumber"].ToString(),
    36                         ClassName = objReader["ClassName"].ToString(),
    37                         ClassId = Convert.ToInt32(objReader["ClassId"])
    38                     });
    39                 }
    40                 return stuList;
    41             }
    42             catch (Exception ex)
    43             {
    44                 throw ex;
    45             }
    46             finally
    47             {
    48                 objReader.Close();
    49             }
    50         }
    51     }
    52 }
    View Code

    SQLServer数据库

    SQLHelper:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Threading.Tasks;
      6 using System.Configuration;
      7 using System.Data;
      8 using System.Data.SqlClient;
      9 
     10 namespace DAL.SQLServer
     11 {
     12     class SQLHelper
     13     {
     14         private static readonly string connString=ConfigurationManager.ConnectionStrings["SqlConnString"].ToString();
     15 
     16         /// <summary>
     17         /// 增、删、改,返回受影响行数
     18         /// </summary>
     19         /// <param name="sql"></param>
     20         /// <returns></returns>
     21         public static int Update(string sql)
     22         {
     23             SqlConnection conn = new SqlConnection(connString);
     24             SqlCommand cmd = new SqlCommand(sql, conn);
     25             try
     26             {
     27                 conn.Open();
     28                 return cmd.ExecuteNonQuery();
     29             }
     30             catch (SqlException ex)
     31             {
     32                 if (ex.Number == 547)
     33                     throw new Exception("该数据已被其它表引用,不能直接删除!");
     34                 else
     35                     throw new Exception("数据库操作异常:" + ex.Message);
     36             }
     37             catch (Exception ex)
     38             {
     39                 throw ex;
     40             }
     41             finally
     42             {
     43                 conn.Close();
     44             }
     45         }
     46         
     47 
     48         /// <summary>
     49         /// 仅得到一条数据的查询
     50         /// </summary>
     51         /// <param name="sql"></param>
     52         /// <returns></returns>
     53         public static object GetSingleResult(string sql)
     54         {
     55             SqlConnection conn = new SqlConnection(connString);
     56             SqlCommand cmd = new SqlCommand(sql, conn);
     57             try
     58             {
     59                 conn.Open();
     60                 return cmd.ExecuteScalar();
     61             }
     62             catch (SqlException ex)
     63             {
     64                 throw new Exception("数据库操作异常:" + ex.Message);
     65             }
     66             catch (Exception ex)
     67             {
     68                 throw ex;
     69             }
     70             finally
     71             {
     72                 conn.Close();
     73             }
     74         }
     75 
     76         /// <summary>
     77         /// 查询得到结果集
     78         /// </summary>
     79         /// <param name="sql"></param>
     80         /// <returns></returns>
     81         public static SqlDataReader GetReader(string sql)
     82         {
     83             SqlConnection conn = new SqlConnection(connString);
     84             SqlCommand cmd = new SqlCommand(sql, conn);
     85             try
     86             {
     87                 conn.Open();
     88                 return cmd.ExecuteReader(CommandBehavior.CloseConnection);
     89             }
     90             catch (SqlException ex)
     91             {
     92                 if (conn.State == ConnectionState.Open)
     93                     conn.Close();
     94                 throw new Exception("应用程序与数据库连接异常:" + ex.Message);
     95             }
     96             catch (Exception ex)
     97             {
     98                 if (conn.State == ConnectionState.Open)
     99                     conn.Close();
    100                 throw ex;
    101             }
    102         }
    103 
    104         /// <summary>
    105         /// 查询得到数据集,前台需要多次筛选数据时使用
    106         /// </summary>
    107         /// <param name="sql"></param>
    108         /// <returns></returns>
    109         public static DataSet GetDataSet(string sql)
    110         {
    111             SqlConnection conn = new SqlConnection(connString);
    112             SqlCommand cmd = new SqlCommand(sql, conn);
    113             SqlDataAdapter da = new SqlDataAdapter(cmd);
    114             DataSet ds = new DataSet();
    115             try
    116             {
    117                 conn.Open();
    118                 da.Fill(ds);
    119                 return ds;
    120             }
    121             catch (SqlException ex)
    122             {
    123                 throw new Exception("数据库操作异常:" + ex.Message);
    124             }
    125             catch (Exception ex)
    126             {
    127                 throw ex;
    128             }
    129             finally
    130             {
    131                 conn.Close();
    132             }
    133         }
    134     }
    135 }
    View Code

    ClassService:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using IDAL;
     7 using Models;
     8 using System.Data;
     9 using System.Data.SqlClient;
    10 
    11 namespace DAL.SQLServer
    12 {
    13     public class ClassService : IClassService
    14     {
    15         public List<StudentClass> GetAllClasses()
    16         {
    17             string sql = "select * from StudentClass";
    18             SqlDataReader objReader = SQLHelper.GetReader(sql);
    19             List<StudentClass> objStuClass = new List<StudentClass>();
    20             while (objReader.Read())
    21             {
    22                 objStuClass.Add(new StudentClass
    23                 {
    24                     ClassId = Convert.ToInt32(objReader["ClassId"]),
    25                     ClassName = objReader["ClassName"].ToString()
    26                 });
    27             }
    28             objReader.Close();
    29             return objStuClass;
    30         }
    31     }
    32 }
    View Code

    StudentService:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using IDAL;
     7 using Models;
     8 using System.Data;
     9 using System.Data.SqlClient;
    10 
    11 namespace DAL.SQLServer
    12 {
    13     public class StudentService : IStudentService
    14     {
    15         public List<Student> GetStudentsByClassId(int classId)
    16         {
    17             StringBuilder sqlBuilder = new StringBuilder("select StudentId,StudentName,Gender,StudentIdNo,Birthday,PhoneNumber,ClassName,Students.ClassId from Students ");
    18             sqlBuilder.Append("inner join StudentClass on StudentClass.ClassId=Students.ClassId ");
    19             if (classId >= 0)//当==-1,说明是选的全部班级,则不需要筛选
    20                 sqlBuilder.Append($"where Students.ClassId={classId} ");
    21             List<Student> stuList = new List<Student>();
    22             SqlDataReader objReader = null;
    23             try
    24             {
    25                 objReader = SQLHelper.GetReader(sqlBuilder.ToString());
    26                 while (objReader.Read())
    27                 {
    28                     stuList.Add(new Student
    29                     {
    30                         StudentId = Convert.ToInt32(objReader["StudentId"]),
    31                         StudentName = objReader["StudentName"].ToString(),
    32                         Gender = objReader["Gender"].ToString(),
    33                         StudentIdNo = objReader["StudentIdNo"].ToString(),
    34                         Birthday = Convert.ToDateTime(objReader["Birthday"]),
    35                         PhoneNumber = objReader["PhoneNumber"].ToString(),
    36                         ClassName = objReader["ClassName"].ToString(),                       
    37                         ClassId = Convert.ToInt32(objReader["ClassId"]),                        
    38                     });
    39                 }
    40                 return stuList;
    41             }
    42             catch (Exception ex)
    43             {
    44                 throw ex;
    45             }
    46             finally
    47             {
    48                 objReader.Close();
    49             }
    50         }
    51     }
    52 }
    View Code

    App.Config配置

    数据库用到了App.Config节点:

     1 <?xml version="1.0" encoding="utf-8" ?>
     2 <configuration>
     3     <startup> 
     4         <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
     5     </startup>
     6   <connectionStrings>
     7     <add name="SqlConnString" connectionString="server=.;DataBase=StudentManageDB;Uid=sa;Pwd=warrenwell"/>
     8     <add name="AccessConnString" connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=StudentManageDB.mdb"/>
     9   <!--Office版本2007以上使用以上Provider;以下:Microsoft.JET.OLEDB.4.0-->
    10   </connectionStrings>
    11   <appSettings>
    12     <add key="DBType" value="SQLServer"/>
    13     <!--<add key="DBType" value="Access"/>-->
    14     </appSettings>
    15 </configuration>
    View Code

    Models实体类

    使用到的实体类

    StudentClass:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Models
     8 {
     9     public class StudentClass
    10     {
    11         public int ClassId { get; set; }
    12         public string ClassName { get; set; }
    13     }
    14 }
    View Code

    Students:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Models
     8 {
     9     public class Student
    10     {
    11         public int StudentId { get; set; }
    12         public string StudentName { get; set; }
    13         public string Gender { get; set; }
    14         public DateTime Birthday { get; set; }
    15         public string StudentIdNo { get; set; }
    16         public int Age { get; set; }
    17         public string CardNo { get; set; }
    18         public string PhoneNumber { get; set; }        
    19         public int ClassId { get; set; }
    20 
    21         public string ClassName { get; set; }
    22     }
    23 }
    View Code

    DALFactory

    DALFactory根据以上App.Config里appSettings节点的key<"DBType">来选择数据库

    DALAccess数据库数据访问创建类:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using System.Configuration;
     7 using IDAL;
     8 using System.Reflection;
     9 
    10 namespace DALFactory
    11 {
    12     public class DataAccess
    13     {
    14         private static string dbType = "DAL."+ConfigurationManager.AppSettings["DBType"].ToString();
    15 
    16         public static IDAL.IClassService CreateClassService()
    17         {
    18             return (IDAL.IClassService)Assembly.Load("DAL").CreateInstance(dbType + ".ClassService");
    19         }
    20 
    21         public static IDAL.IStudentService CreateStudentService()
    22         {
    23             return (IDAL.IStudentService)Assembly.Load("DAL").CreateInstance(dbType + ".StudentService");
    24         }
    25     }
    26 }
    View Code

    应用到了反射,里面Load()里面是数据库的命名空间名称,CreateInstance()里面是相应DAL的完全限定名:命名空间名称.相应Serivce名。

    BLL

    我们把数据访问的内容全部放到BLL里面,从而完全断绝UI与DAL的耦合。

    ClassManager:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using DALFactory;
     7 using Models;
     8 using IDAL;
     9 
    10 namespace BLL
    11 {
    12     public class ClassManager
    13     {
    14         IDAL.IClassService objService = DALFactory.DataAccess.CreateClassService();
    15         public List<StudentClass> GetAllClasses()
    16         {
    17             return objService.GetAllClasses();
    18         }
    19     }
    20 }
    View Code

    StudentManager:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using DALFactory;
     7 using Models;
     8 using IDAL;
     9 
    10 namespace BLL
    11 {
    12     public class StudentManager
    13     {
    14         IDAL.IStudentService objService = DALFactory.DataAccess.CreateStudentService();
    15         public List<Student> GetStudentsByClassId(int classId)
    16         {
    17             return objService.GetStudentsByClassId(classId);
    18         }
    19     }
    20 }
    View Code

    UI

    仅写了查询班级与学生(UI设计见下面结果展示):

     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Data;
     5 using System.Drawing;
     6 using System.Linq;
     7 using System.Text;
     8 using System.Threading.Tasks;
     9 using System.Windows.Forms;
    10 using BLL;
    11 using Models;
    12 
    13 namespace AbstractFactoryDemo
    14 {
    15     public partial class FrmQuery : Form
    16     {
    17         public FrmQuery()
    18         {
    19             InitializeComponent();
    20 
    21             List<StudentClass> stuClass = new List<StudentClass>()
    22             {
    23                 new StudentClass {ClassId=-1,ClassName="全部班级" }
    24             } ;
    25             stuClass.AddRange(new ClassManager().GetAllClasses());
    26 
    27             this.cboStudentClass.DataSource = stuClass;
    28             this.cboStudentClass.DisplayMember = "ClassName";
    29             this.cboStudentClass.ValueMember = "ClassId";
    30 
    31             this.dgvStudentList.AutoGenerateColumns = false;
    32         }
    33 
    34         private void btnQuery_Click(object sender, EventArgs e)
    35         {
    36             this.dgvStudentList.DataSource = new StudentManager().GetStudentsByClassId(Convert.ToInt32(this.cboStudentClass.SelectedValue));
    37         }
    38     }
    39 }
    View Code

    结果展示

    我们可以通过配置App.Config的相应节点来控制访问哪个数据库。

    比如,我们先访问SQLServer,就这样:

    访问结果:

     再去访问Access:

    访问结果:

    故意将两个数据库的数据格式不一致,比较容易看出来差别。

    至此,抽象工厂设计模式完成。

    相应源代码+数据库脚本

     https://files.cnblogs.com/files/EasonDongH/%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%BA%90%E4%BB%A3%E7%A0%81And%E6%95%B0%E6%8D%AE%E5%BA%93%E8%84%9A%E6%9C%AC.zip

    注意点

    有个地方需要注意,关于DAL.dll文件,如果提示不存在,则需要手动到DAL程序集下将该DAL.dll复制到项目下;如果提示“源文件与模块不一致”这样的错误,则表示你的DAL有做修改,重新生成一下DAL,再次重新将dll文件复制过去。这是经验之谈,暂未更好的解决方案,等待指教。

  • 相关阅读:
    MySQL--字符集参数
    MySQL--字符集基础
    Cassandra基础2
    Cassandra基础
    Cassandra -- Cassandra 3.0版本安装
    Cassandra Demo--Python操作cassandra
    MySQL--批量插入导致自增跳号问题
    MySQL Disk--SSD和HDD的性能
    MySQL Lock--并发插入导致的死锁
    TCL-视图
  • 原文地址:https://www.cnblogs.com/EasonDongH/p/8116890.html
Copyright © 2011-2022 走看看