现在的位置: 首页 > 综合 > 正文

逻辑层=外观层?

2013年06月25日 ⁄ 综合 ⁄ 共 3629字 ⁄ 字号 评论关闭

引言:

  在机房收费系统中,因为自己走过的一个‘误区’,体会到了一个很有意思的问题:三层开发中业务逻辑层+外观模式导致业务逻辑层被架空。原本该是各种业务逻辑判断的B层,一下被新加进来的外观层“越俎代庖”了。这样,原本三设计中的核心:业务逻辑层一下成了鲁迅在其文章中所言:有原先殷实的家境一下子家道中落,被外观层所取代。

基础知识:

  业务逻辑层:作为系统架构中体现核心价值的部分,其关注点集中在业务规则的制定、业务流程的实现等与业务需有关的系统设计。主要用于做一些有效性验证的工作,以更好的保证程序运行的健壮性。如完成数据添加、修改和查询业务等;不允许指定的文本框中输入空字符串,数据格式是否正确以及数据类型验证;用户权限的合法性判断等;通过以上的诸多判断以决定是否将操作继续向后传递,尽量保证程序的正常运行(官话)。拿我们机房收费系统来说,是各个用例功能的实现,都应该在B层有对应的实现(经典三层开发状态下而言),这也是我们经常提到的:业务逻辑层尽量向UI层靠近(B层对应D层的也行,各有各的好处吧)


  外观模式:为仔细系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统容易使用;外观模式最大的特点将细粒度的对象包装成粗粒度的对象,应用程序通过访问这个外观对象,来完成细粒度对象的调用。


  我自己的感觉,看着师哥师姐合作版机房收费系统,在用户界面层和数据访问层中间加入了一个外观层,通过这个外观层,来封装UI层单个用例所需要的各个业务逻辑实现,从而减少了UI层和BLL层之间的依赖关系,增强了系统的稳定与健壮性。但是,这样就出现一个问题:一些复杂的业务逻辑实现用外观层可以很便捷的实现,但是一些简单的业务功能如果使用外观,就会产生一种冗余的行为;例如我们如果在D层返回的是一个Datatable
类型的数据,添加外观
层之后,因为UI层没有对D层的引用,而是通过外观层来实现的,这样就导致B层会继续想外观层返回一个Datatable类型的数据,B层就是一个简单的过渡?那样要B层做什么?这样的话符合原先三层开发中B层的描述么?


举例说明:

 机房收费系统中,用户退卡业务功能,其大致流程:

  1 判断用户是否注册

  2判断用户是否正在上机 

  3只有当用户注册且用户没有上机条件下才可以进行退卡操作:

StuInfoBLL

''' <summary>    ''' 检索学生信息
    ''' </summary>
    ''' <param name="Student"></param>
    ''' <returns>dtStudentInfo</returns>
    ''' <remarks>返回某个注册学生的信息表</remarks>
    Public Function SelectStudent(ByVal Student As Entity.StudentInfoEntity) As DataTable
        Dim dtStudentInfo As DataTable
        IStudentInfo = dataAccess.CreateStudent
        dtStudentInfo = IStudentInfo.SelectStudent(Student)
        Return dtStudentInfo
    End Function


StuOnlineBLL

''' <summary>	    ''' 查询正在上机学生信息
	    ''' </summary>
	    ''' <param name="Student"></param>
	    ''' <returns>dtOnlineStu</returns>
	    ''' <remarks>获取正在上机学生信息</remarks>
	    Public Function SelectOnlineStu(ByVal Student As Entity.StuOnlineEntity) As DataTable
	
	        Dim dtOnlineStu As DataTable
	        IOnline = dataAccess.CreateOnline
	        dtOnlineStu = IOnline.SelectOnlineStu(Student)
	        Return dtOnlineStu
	
	    End Function

CancelCardBLL

 ''' <summary>    ''' 将退卡信息添加到退卡表中
    ''' </summary>
    ''' <param name="CancelCard"></param>
    ''' <returns>Boolean</returns>
    ''' <remarks>如果添加退卡记录成功返回true 否则返回false</remarks>
    Public Function AddCancelCard(ByVal CancelCard As Entity.CancelCardEntity) As Boolean
        Icancelcard = dataAccess.CreateCancelCard
        If Icancelcard.AddCancelCard(CancelCard) = True Then
            Return True
        Else
            Return False
        End If
    End Function

外观层

   Dim bllCancelCard As New BLL.CancelCardBLL '
    Dim bllStuInfo As New BLL.StudentInfoBLL '用来判断用户是否存在,并获取相应的用户信息
    Dim bllOnlineStu As New BLL.OnlineBLL  '用来判断用户是否正在上机
    Dim dtStuInfo As DataTable
    Dim dtOnlineStu As DataTable
''' <summary>
    ''' 退卡外观层
    ''' </summary>
    ''' <param name="CardInfo"></param>
    ''' <returns>Boolean</returns>
    ''' <remarks>1 用户是否存在 2用户是否上机 3 向退卡表中添加结账信息 4 从注册表中删除</remarks>
    Function CancelCard(ByVal CardInfo As Entity.StudentInfoEntity, CancelInfo As Entity.CancelCardEntity) As Boolean
        dtStuInfo = bllStuInfo.SelectStudent(CardInfo)
        '用户尚未注册
        If dtStuInfo.Rows.Count = 0 Then
            Throw New Exception("该账户尚未注册,请选择其它账户进行操作")
        Else
            '用户正在上机
            If dtOnlineStu.Rows.Count = 0 Then
                Throw New Exception("该账户正在上机,请下机之后再进行退卡操作")
            Else
                
                '从注册表中删除成功,并将退卡信息添加到退卡表中成功 返回true 否则 返回false
                CancelInfo.CancelCardID = Trim(CardInfo.StuCardID)
                CancelInfo.CancelCash = dtStuInfo.Rows(0).Item(7)
                CancelInfo.CancelDate = Date.Today
                CancelInfo.CancelTime = TimeOfDay
                CancelInfo.CancelStatus = "已结账"
                CancelInfo.CancelUserID = dtStuInfo.Rows(0).Item(9)
                If bllCancelCard.AddCancelCard(CancelInfo) = True And bllStuInfo.DeleteStudent(CardInfo) = True Then
                    Return True
                Else
                    Return False
                End If
            End If
        End If
End Function

  像这种相对而言,比较复杂的业务实现,用到外观层就会简化很多。如果用户退卡,那么只需要实例化外观层用户退卡类,然后实现其方法就可以了。有利也有‘弊’,假如我要获取用户工作记录这些相对简单的业务功能,就会产生系统资源的浪费;我本来已经从D层返回一个Datatable 类型的值了,但是因为UI层没有相应的引用,导致必须将这个Datatable类型的值再返回到外观层,B层就是简单的过渡,没有任何‘存在感’!对于这个问题,我的想法是:删除外观层,将上述例子中在外观层中的代码实现,转移到B层用户退卡业务逻辑中去;这样对于那些简单的业务逻辑,也就产生传递两次导致系统资源浪费的情况;

个人感觉:

  实际上外观模式,就是一个业务逻辑‘完美’的B层;一个逻辑良好的B层可以也同样是一个完美的外观层。开发人员将B层的业务逻辑设计的很好的,那么不使用外观模式,同样可以对UI层提供一个统一的接口!将UI层所需要的各种方法封装在B层,貌似没有用到外观模式的型,但实质却是外观模式的魂:对上层提供统一的接口而不管具体的复杂业务逻辑实现。当然,一个业务逻辑良好的B层也不是简单容易实现的,这就需要在实践中具体而仔细的琢磨了。(完)

抱歉!评论已关闭.