【机房重构】——观察者模式解决三种下机

     引言

  对于重构来说我们知道在机房收费这个系统中有三种下机——正常下机、强制所有下机、选择强制下机。在第一遍的时候我们就是在做完正常下机以后,然后复制代码来完成,在重构的时候有了设计模式作为基础,我们可以用观察者模式轻松搞定这三种下机。

  基础篇

 基本概念:观察者模式又叫做发布-订阅模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化的时,会通知所有的观察者对象,是他们能够自动更新自己。
 基本类图:

               【机房重构】——观察者模式解决三种下机_第1张图片
  应用场景:当一个对象的改变需要同时改变其他对象,并且他不知道具体有多少对象有待改变时,应该考虑使用观察者模式。总的来讲,观察者模式所做的工作其实就是子啊解除耦合,让耦合的双方都依赖于抽象而不是依赖于具体,从而是得各自的变化都不会影响另一边的变化!

  实战篇

 在上面介绍了关于观察者模式的一些基本知识,现在就借助机房重构这个机会小试一把。因为我在下机的过程中需要进行如下判断:卡号是否存在、卡号是否正在上机、是否插入上机记录表等。这些都是每个下机都要判断的,所以用观察者模式来解决这个问题。
 类图如下:

 【机房重构】——观察者模式解决三种下机_第2张图片
部分代码如下:
'**********************************************
'说明:在下机的时候用观察者模式,抽象观察者
'命名空间:BLL
'机器名称:晓
'创建日期:2015/1/4 22:50:10
'作者:郑浩
'版本号:V1.00
'**********************************************
Public MustInherit Class SubjetBll
    Private ilist As IList(Of ObserverBLL) = New List(Of ObserverBLL)
    ''' <summary>  
    ''' 添加观察者  
    ''' </summary>  
    ''' <param name="observer">抽象观察者类</param>  
    Public MustOverride Sub Attach(ByVal observer As ObserverBLL)

    ''' <summary>  
    ''' 去除观察者  
    ''' </summary>  
    ''' <param name="observer">抽象观察者类</param>  
    Public MustOverride Sub Detach(ByVal observer As ObserverBLL)


    ''' <summary>  
    ''' 通知观察者  
    ''' </summary>  
    Public MustOverride Sub Notify(ByVal online As Entity.EN_CardInfo)
 
End Class

'**********************************************
'说明:抽象的观察者
'命名空间:BLL
'机器名称:晓
'创建日期:2015/1/4 22:53:55
'作者:郑浩
'版本号:V1.00
'**********************************************
Public MustInherit Class ObserverBLL
    '定义一个抽象的更新的方法
    Public MustOverride Sub Update(ByVal online As Entity.EN_CardInfo)
End Class

说明:上机的第一步检查卡号时候存在
'命名空间:BLL
'机器名称:晓
'创建日期:2015/1/3 8:20:17
'作者:郑浩
'版本号:V1.00
'**********************************************
Imports IDAL
Imports BLL.OnLineStateBLL
Public Class IsExitCardNoBLL : Inherits OnLineStateBLL

    Public Overrides Sub online(ByVal cardinfo As Entity.EN_CardInfo, ByVal upline As BLL.UpLineBLL)

        Dim factory As New DAL.Factory
        Dim Ionline As IOnOffLine
        Ionline = factory.CreateOnOffLine
        Dim dt As DataTable
        dt = Ionline.CheckCardInfo(cardinfo)
        '判断卡号是否存在
        If (dt.Rows.Count = 0) Then
            MsgBox("卡号不存在")
        Else
            cardinfo.StudentName = dt.Rows(0).Item(3)
            cardinfo.Status = "正常上机"
            upline.SetNextState(New BalanceStateBLL)
            upline.CardOnLine(cardinfo)

        End If

    End Sub
End Class

'**********************************************
'说明:插入上机记录
'命名空间:BLL
'机器名称:晓
'创建日期:2015/1/5 23:45:31
'作者:郑浩
'版本号:V1.00
'**********************************************
Imports BLL.ObserverBLL
Imports IDAL
Public Class OInsertOnLineRecord : Inherits BLL.ObserverBLL

    Public Overrides Sub Update(online As Entity.EN_CardInfo)
        If Entity.PublicVariables.observeflag = "用户未上机" Then

        Else
            '首先在上机表中读取数据,然后赋给实体
            Dim factory As New DAL.Factory
            Dim Ionlining As IOnLining
            Ionlining = factory.CreateOnLining
            Dim dt As DataTable
            dt = Ionlining.IsCardNoLining(online)
            '计算消费时间
            Dim offdate As Date  '下机日期
            offdate = Date.Today()
            Dim offtime As String '下机时间
            offtime = Date.Now.ToString("hh:mm:ss")
            Dim spenttime As Double    '消费的时间
            Dim realitytime As Double    '实际消费时间
            Dim spentmoney As Integer    '消费金额
            Dim type As String          '用户类型
            Dim cardbalance As Integer

            '调用获得基本数据方法来获得基本数据
            Dim basicdatafactory As New DAL.Factory
            Dim Ibasicdata As ISetBasicData
            Ibasicdata = basicdatafactory.CreateBasicData
            Dim table As DataTable
            table = Ibasicdata.GetBasicData()
            '计算实际消费时间
            realitytime = 0
            spenttime = DateDiff(DateInterval.Minute, dt.Rows(0).Item(3), offdate) + DateDiff(DateInterval.Minute, CDate(dt.Rows(0).Item(4)), CDate(offtime))

            '判断消费时间和准备时间的大小
            If (spenttime < table.Rows(0).Item(5)) Then
                realitytime = 0
            ElseIf (spenttime < table.Rows(0).Item(4)) Then
                realitytime = table.Rows(0).Item(4)
            Else
                realitytime = spenttime
            End If
            '调用检查卡号的方法,来获取用户类型和余额

            Dim cardfactory As New DAL.Factory
            Dim Ionline As IOnOffLine
            Ionline = cardfactory.CreateOnOffLine

            Dim carddt As DataTable
            carddt = Ionline.CheckCardInfo(online)
            type = carddt.Rows(0).Item(15)     '获得用户类型
            cardbalance = carddt.Rows(0).Item(8)  '获得卡内余额



            Dim basicdata As New Entity.EN_BasicData
            basicdata.FixPrice = table.Rows(0).Item(1)
            basicdata.TempPrice = table.Rows(0).Item(2)

            '调用CashFactory 来计算消费金额
            Dim cashfactory As BLL.CashFactory = New CashFactory()
            Dim csuper As BLL.CashSuper
            csuper = cashfactory.CreateCashAccept(type)
            spentmoney = csuper.AcceptCash(basicdata, realitytime)

            '定义一个实体用来插入上机记录
            Dim onlinerecord As New Entity.EN_CardInfo
            onlinerecord.CardNo = dt.Rows(0).Item(1)
            onlinerecord.StudentName = dt.Rows(0).Item(2)
            onlinerecord.OnDate = dt.Rows(0).Item(3)
            onlinerecord.OnTime = dt.Rows(0).Item(4)
            onlinerecord.OffDate = offdate
            onlinerecord.OffTime = offtime
            onlinerecord.ConsumeTime = spenttime
            onlinerecord.ConsumeMoney = spentmoney
            onlinerecord.Balance = cardbalance - spentmoney
            onlinerecord.WorkerComputer = System.Net.Dns.GetHostName().ToString()
            onlinerecord.Status = online.Status
            onlinerecord.Type = type
            onlinerecord.UserName = Entity.PublicVariables._username

            '用于传给U层显示在文本框中
            Entity.PublicVariables.onlinerecordinfo = onlinerecord

            '调取学生表中的信息,用于填写U层的学生的基本信息
            Dim Cfactory As New DAL.Factory
            Dim CIonline As IOnOffLine
            CIonline = factory.CreateOnOffLine
            Dim Cdt As DataTable
            Cdt = Ionline.CheckCardInfo(online)
            '获得学生的基本信息后,赋给全局变量,然后传递给U层
            Entity.PublicVariables.StudentBasicInfo = Cdt
            '更新上机记录表中的数据
            Dim Ionlinerecord As IOnOffLine
            Dim result As Integer
            Ionlinerecord = factory.CreateOnOffLine
            result = Ionlinerecord.UpdateLineRecord(onlinerecord)

            If result = 0 Then

                MsgBox("更新上机记录失败")

            End If

        End If
    End Sub
End Class
<pre name="code" class="vb">**********************************************
'说明:具体的观察者
'命名空间:Facade
'机器名称:晓
'创建日期:2015/1/6 0:23:04
'作者:郑浩
'版本号:V1.00
'**********************************************
Public Class FacadeFormalOnLine
    ''' <summary>
    ''' 正常上机
    ''' </summary>
    ''' <param name="online"></param>
    ''' <remarks></remarks>
    Public Sub FormalOnLine(ByVal online As Entity.EN_CardInfo)
        Dim Fformalonline As New BLL.NormalOffLine
        Fformalonline.Attach(New BLL.OCardIsExist)
        Fformalonline.Attach(New BLL.OCardIsOnLine)
        Fformalonline.Attach(New BLL.OInsertOnLineRecord)
        Fformalonline.Notify(online)

    End Sub
End Class


 
  

 思考

 我们都已经做过了一遍机房收费系统,我们根据需求会发现这样一个问题,当我们判断到卡号不存在时,会给出一个提醒“卡号不存在”,这时候后面的判断就不用进行了,直接退出,但是在观察这模式会自动遍历这些观察者,这就造成重复提示的缺陷,为了避免这个缺陷,我在实体层定义了一个全局变量用来在B层控制是否进行下一个判断。虽然达到做了目的,但是总感觉这样的办法不是最好的,这个问题正在研究中,如果哪位大神有好的想法,请留言提示!

 小结

 其实下机和上机时计算消费的判断思路差不多,但是为了更好的联系设计模式的知识,所以采用了不同的模式,在上机计算消费时采用了状态模式,详见【机房重构】——策略模式+简单工厂计算消费,在重构的时候主要是对前面学习的这些编程的思想和知识的一个灵活运用,所以在做的时候尽可能的采用不同思路和想法从多个方面来完成相应的功能,在这个阶段的运用没有对错之分,只有用过以后才能在下一次编程的时候更加灵活的运用它,所有希望同学能打开思路进行机房重构,Come On!!1

你可能感兴趣的:(设计模式,架构,VB.NET)