终于开始机房重构了,在此之前,我用三层敲了机房的部分功能,感觉还不错,现在真正到了七层,还是蛮紧张的。话不多说,开始机房的七层登录。
我发现好多伙伴写七层登录的时候,都喜欢分析一下包图,那我也来简单分析一下吧。
包图展现的无非就是引用关系,U层引用外观,外观引用B层,B层通过工厂创建一个接口返回给B层,然后B层通过这个接口连接到实现接口的D层,完成数据的增删改查。接下来,我说几个很重要的层。
通过配置文件可以很方便的更改数据库,如果需要更改数据库,我只需要把配置文件中的SqlDAL改成其他数据库名字就ok了。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="ConnStr" value="server=.;database="数据库名字";User ID=**;password=******"/> <add key="DB" value="SqlDAL"/> </appSettings> </configuration>
B层我觉得是相对重要的一层,因为几乎所有的逻辑判断全在B层,这里是思维闪光的地方。
public bool UserBLL(Entity.UserInfo UserInfo) { Factory.Factory fact = new Factory.Factory();//实例化工厂 IDAL.IDAL idal = fact.CreateUser();//调用工厂方法创建接口 DataTable table= idal.selectUser(UserInfo);//接受D层的返回值 bool flag; if (table.Rows.Count==0)//返回的DataTable类型,如果它的行数等于0,说明没有符合该帐号密码的用户 { flag = false; } else { flag = true; } return flag; }
工厂的作用就是将反射的接口返回给B层,供B层连接D层使用。
string StrDB = System.Configuration.ConfigurationManager.AppSettings["DB"];//接收来自配置文件的数据 public IDAL.IDAL CreateUser() { string ClassName = StrDB + "." + "DAL";//DAL层的类名 return (IDAL.IDAL)Assembly.Load(StrDB).CreateInstance(ClassName);//反射加工厂的应用 }
D层的作用就是连接数据库,进行增删改查,然后将结果返回。
public DataTable selectUser(Entity.UserInfo UserInfo) { SqlParameter[] sqlParams = {new SqlParameter("@userID", UserInfo.UserID),new SqlParameter("@PassWord",UserInfo.PassWord)}; string sql = @"SELECT * FROM [T_USERS] WHERE UserID=@UserID and PassWord =@PassWord"; DataTable table =SqlDAL.SQLHelper.GetDataTable(sql, CommandType.Text, sqlParams); return table; }
public static string ConnectionString = ConfigurationManager.AppSettings["ConnStr"]; /// <summary> ///执行带参数的查询方式,返回值为表。 /// <param name="cmdTxt" >参数cmdText为所要执行的sql语句</param > /// <param name=" cmdType">查询时的查询方式</param> /// <param name="paras" >查询时的命令参数</param> /// <returns >查询后以表的形式返回,</returns > /// </summary> /// <remarks></remarks>
public static DataTable GetDataTable(string cmdTxt, CommandType cmdType, SqlParameter[] paras) { SqlConnection conn = new SqlConnection(ConnectionString); //创建数据库的连接 SqlCommand cmd = default(SqlCommand); //定义命名变量。 DataSet adataset = null; //定义数据适配器,DataSet类表示一个存放于内存中的数据缓存 SqlDataAdapter adaptor = default(SqlDataAdapter); //SqlDataAdapter类目的是填充DataSet cmd = new SqlCommand(cmdTxt, conn); //在conn上面执行实例化命令变量,并执行语句cmdtype cmd.CommandType = cmdType; //命令执行的类型 cmd.Parameters.AddRange(paras); //命令执行的参数 adaptor = new SqlDataAdapter(cmd); //初始化 SqlDataAdapter 类的新实例,用指定的 cmd 作为 SelectCommand 的属性 adataset = new DataSet(); try { if (conn.State == ConnectionState.Closed) { conn.Open(); } adaptor.Fill(adataset); //向adaptor对象中填充查询的数据 } catch (Exception ex) { Interaction.MsgBox(ex.Message); } finally { if (conn.State == ConnectionState.Open) { conn.Close(); } } return adataset.Tables[0]; //获取包含在 DataSet 中的表的集合。 }这个是参考的一个师哥的博客,但是我发现这个SqlHelper不全,因为它每次访问数据库都会有一个返回值,而我如果要去更新表中的东西如修改密码时,它显然不是最好用的,所以我根据这个有返回值的SqlHelper,自己编写了一个没有返回值的SqlHelper。
public static bool ExecuteNonQuery(string cmdTxt, CommandType cmdType, SqlParameter[] paras) { using (SqlConnection conn = new SqlConnection(ConnectionString)) { //创建数据库的连接 SqlCommand cmd = default(SqlCommand); //定义命名变量。为什么要用default? cmd = new SqlCommand(cmdTxt, conn); //在conn上面执行实例化命令变量,并执行语句cmdtype cmd.CommandType = cmdType; //命令执行的类型 cmd.Parameters.AddRange(paras); //命令执行的参数 conn.Open(); int enq = cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery(); bool flag; if (enq > 0) { flag = true; } else { flag = false; } return flag; } }
七层的代码相对于三层来说,我觉得多不了多少,但是它带来的便利是相当大的,外观模式在机房收费系统中的作用体现不大,但是反射+抽象工厂的应用,极大的方便了该系统更换数据库,只需要改一行代码,就能在完全不知道内部代码是什么的情况下完成数据库的更换,真正体现了“对修改关闭,对扩展开放”这句话。