打开思维,让分层飞一会
- 认识分层:
做开发也有几年了,在开发软件的过程中,分层式结构是最常见的,也是非常重要的。
其实,分层只是一种思想,与层数无关,不管是分为三层,还是五层,抑或是七层,这些分法都是为了让我们的项目适应变化,可重用,方便程序员的开发。
那些所谓的代名词:
表示层:这一层是给用户的界面;就是和用户交互的,用于显示和接收用户输入的数据的。
数据层:这一层就是负责数据库的访问,其实就是对数据表的增删改查等操作。
业务逻辑层:这一层处于表示层和数据层中间,可以看出这一层的重要性。我给他起了另外一个名字叫“华丽的承上启下”。这一层主要完成业务的规则定制、业务流程实现等任务。
各司其职,分层治之:
我们将整个项目分层,这样可以做到各司其职,各管各家,分开治之。
我们的开发人员可以只关注更个结构中的其中一层,其余的都可以不用去照顾,这样每个成员都有自己的关注点,使分工很明确。
维护也就显得非常容易,只要用新的实现替换原有层次的实现即可;
分层治之,可以让层层之间依赖性降低,达到解耦的目的。
我们也很容易的发现,数据层的代码复用率高,而且分层之后各层之间的逻辑也得到了复用。
我们在开发的时候也可以用多语言进行开发。
层,要合理的去分:
分层就像设计模式一样,要想用好不是容易的事情,我也是正在摸索中,在项目中积累经验。
但是我知道,层不是说分三层就分三层,分五层就五层,七层就七层的,要看具体的项目工程。一如设计模式,不是说看懂了这个设计模式,我做项目中一定要用到它;用不好有时候会吃亏的。
项目实战--分一回:
rose架构图:

表示层代码:
'''''' 单击确定按钮'''''''''''' 2011-3-20 13:21 by lfsf802Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.ClickIf Trim(txtUsername.Text) = "" Or Trim(txtPwd.Text) = "" Or Trim(cmbStatus.Text) = "" ThenMsgBox("信息不能为空")wrongReturn()Exit SubEnd IfIf blluserInfo.checkRecord(Trim(txtUsername.Text), Trim(txtPwd.Text), Trim(cmbStatus.Text)) ThenfrmMain.show()ElseMsgBox("输入信息错误,请您重新输入")wrongReturn()ReturnEnd IfEnd Sub
业务逻辑层代码:
'''''' 判断登录'''''' 用户名''' 密码''' 身份''' 是否登录成功''' 2011-3-20 15:14 by lfsf802Public Function checkRecord(ByVal userName As String, ByVal password As String, ByVal status As String) As BooleanentityUserInfo.UserName = userNameDim entityuser As New Entity.UserInfoiuserinfo = dataaccess.CreateUserInfoentityuser = iuserinfo.ReturnRecord(entityUserInfo)If entityuser.Password = password And entityuser.StatusType = status ThenReturn TrueElseReturn FalseEnd IfEnd Function'''''' 返回一条用户信息记录'''''' 一条用户信息''' 一条用户信息记录''' 2011-3-19 16:08 by lfsf802Public Function ReturnRecord(ByVal entityUserInfo As Entity.UserInfo) As Entity.UserInfoiuserinfo = dataaccess.CreateUserInfoReturn iuserinfo.ReturnRecord(entityUserInfo)End Function
数据层:
这里用了抽象工厂设计模式,并且用到了反射技术和配置文件来辅助抽象工厂。
'==============================================================='这个是用反射+抽象工厂的数据库访问方式,我们考虑的是可以不在程序'写具体让实例化那个类,而是根据db的值来去某个地方找应该实例化哪个'类,这样就和select说再见了。'用到反射技术,将greateInstance里面的变量值初始化成想要的类,而实'例化的依据就是db变量来决定的。这样就除去了switch判断的麻烦。'================================================================Private ReadOnly AssemblyName As String = "DAL"'这是反射+配置文件实现数据库访问方式,这样我们只要在配置文件中写明'是哪个数据库就ok了,连dataAccess类也不用更改了Private ReadOnly db As String = System.Configuration.ConfigurationSettings.AppSettings("DB")'Private ReadOnly db As String = "sql"'''''' 实例化用户表类'''''' 用户表类''' 2011-3-23 9:57 by cjqPublic Function CreateUserInfo() As IUserInfoDim className As String = AssemblyName + "." + db + "UserInfo"Return CType(Assembly.Load(AssemblyName).CreateInstance(className), IUserInfo)End Function
接口层:
'''''' 检查一条记录'''''' 一条记录''' 是否存在这样一条记录''' 2011-3-19 14:56 by cjqFunction checkRecord(ByVal entityUserInfo As Entity.UserInfo) As Boolean'''''' 返回一条记录'''''' 一条记录''' 一条用户记录''' 2011-3-19 14:56 by cjqFunction ReturnRecord(ByVal entityUserInfo As Entity.UserInfo) As Entity.UserInfo
数据持久层(在这里笔者参数传递可以换成存储过程):
在这里小论一下存储过程:
在程序逻辑中写SQL语句是很难处理复杂业务逻辑的,困难的引号匹配,复杂的字符串拼接过程,以及字符串拼接过程中的效率损失是我们不得不考虑的。
于是,处理复杂逻辑,如复杂的事务处理时,存储过程几乎成了唯一的方法。但是,存储过程一样有着他的致命缺点,就是他的移植性很差:当我们的项目更换数据库时,我们就要把存储过程完整地去拷贝到另外一个数据库,然后考虑他们的兼容问题;当我们修改数据层访问代码时,我们需要动的不再是应用程序服务器的代码,而是数据库端的代码,这是稍显痛苦的地方。(还是那句,没有完美的,只有最合适的)
'''''' 检查一条记录'''''' 一记录''' 是否存在这样一条记录''' 2011-3-19 20:32 by lfsf802Public Function checkRecord(ByVal entityUserInfo As Entity.UserInfo) As Boolean Implements Interfaces.IUserInfo.checkRecordDim sql As String = "select * from UserInfo where userName=@userName"Dim conn As SqlConnection = New SqlConnection(connStr)Dim cmd As SqlCommand = New SqlCommand(sql, conn)Dim sqlParam As SqlParametersqlParam = New SqlParameter("@userName", SqlDbType.VarChar)sqlParam.Value = entityUserInfo.UserNamecmd.Parameters.Add(sqlParam)Dim sdr As SqlDataReader = NothingTryconn.Open()sdr = cmd.ExecuteReader()sdr.Read()If (sdr.HasRows = True) ThenReturn TrueElseReturn FalseEnd If'Return cmd.ExecuteNonQuery() > 0Catch ex As ExceptionReturn FalseFinallyIf Not IsNothing(conn) Thenconn.Close()conn = NothingEnd IfIf Not IsNothing(cmd) Thencmd.Dispose()cmd = NothingEnd IfEnd TryEnd Function'''''' 返回一条用户信息记录'''''' 一条用户信息''' 一条用户信息记录''' 2011-3-19 16:06 by lfsf802Public Function ReturnRecord(ByVal entityUserInfo As Entity.UserInfo) As Entity.UserInfo Implements Interfaces.IUserInfo.ReturnRecordDim sql As String = "select * from UserInfo where userName=@userName"Dim conn As SqlConnection = New SqlConnection(connStr)Dim cmd As SqlCommand = New SqlCommand(sql, conn)Dim sqlParam As SqlParametersqlParam = New SqlParameter("@userName", SqlDbType.VarChar)sqlParam.Value = entityUserInfo.UserNamecmd.Parameters.Add(sqlParam)Dim sdr As SqlDataReader = NothingTryconn.Open()sdr = cmd.ExecuteReader()While sdr.ReadentityUserInfo.UserName = Trim(sdr.GetString(0))entityUserInfo.Password = Trim(sdr.GetString(1))entityUserInfo.StatusType = Trim(sdr.GetString(2))entityUserInfo.ComputerLabNo = Trim(sdr.GetInt32(3))entityUserInfo.TeacherName = Trim(sdr.GetString(4))End WhileReturn entityUserInfoCatch ex As ExceptionReturn NothingFinallyIf Not IsNothing(conn) Thenconn.Close()conn = NothingEnd IfIf Not IsNothing(cmd) Thencmd.Dispose()cmd = NothingEnd IfEnd TryEnd Function
实体层(mapping数据库):
Public Class UserInfoPrivate _intComputerLabNo As IntegerPrivate _strPassword As StringPrivate _strStatusType As StringPrivate _strTeacherName As StringPrivate _strUserName As String'''''' 机房号'''''''''''' 2011-3-14 15:26 by lfsf802Public Property ComputerLabNo() As IntegerGetReturn _intComputerLabNoEnd GetSet(ByVal value As Integer)_intComputerLabNo = valueEnd SetEnd Property'''''' 用户名'''''''''''' 2011-3-14 15:27 by lfsf802Public Property UserName() As StringGetReturn _strUserNameEnd GetSet(ByVal value As String)_strUserName = valueEnd SetEnd Property'''''' 口令密码'''''''''''' 2011-3-14 15:28 by lfsf802Public Property Password() As StringGetReturn _strPasswordEnd GetSet(ByVal value As String)_strPassword = valueEnd SetEnd Property'''''' 身份类型'''''''''''' 2011-3-14 15:29 by lfsf802Public Property StatusType() As StringGetReturn _strStatusTypeEnd GetSet(ByVal value As String)_strStatusType = valueEnd SetEnd Property'''''' 教师姓名'''''''''''' 2011-3-14 15:30 by lfsf802Public Property TeacherName() As StringGetReturn _strTeacherNameEnd GetSet(ByVal value As String)_strTeacherName = valueEnd SetEnd PropertyEnd Class
飞了一回,你飞了吗?
分层,到这里就唠叨完了,不知道读者对三层有所了解?可以自己做一个小的demo试试哦!
分层,其实没有那么困难,关键是看思维能不能打开,能不能让自己飞起来,相信自己,飞一回试试!!!
最后:
没有完美的分层,只有适合项目工程的分层;但是你是完美的,要相信自己!






浙公网安备 33010602011771号