机房重构——观察者模式上下机


上下机折腾了好几天,本着学习的目的用的是观察者模式。深刻的感受到上下机不适合用观察者。但是如果非要使,也不是不可以~~

机房重构——观察者模式上下机_第1张图片

上下机使用观察者的问题分析


观察者模式在客户端实例化一个具体的通知者,具体通知者中加上具体的观察者,然后使用具体通知者的Notify方法,通知几个具体观察者更新,这几个具体观察者是平级的没有先后循序的,所以更新是同步的,而且他们的更新都没有什么返回值。

但是上下机用观察者就会出现几个问题。把功能检查卡号是否存在并没有退卡如果符合条件返回卡和学生信息,检查卡号是否正在上机,把上机信息 添加到上下机表,下机算钱更新上下机表作为具体观察者;把上机,正常下机,强制全部下机,强制部分下机作为具体通知者。问题一:以上机为例,使用通知这一个方法,就要使检查卡号是否存在,检查是否正在上机,添加上机记录三个类同时使用更新的方法,这三个类之间的先后顺序如何规定? 问题二:这三个类的返回值是不同类型的,检查卡号是否存在,如果符合条件返回的是泛型,而另两个类返回的boolean。

查了师哥师姐的博客,用这个模式的基本上都用的全局变量。我不想用全局变量,解耦不彻底,并且都U层还得判断先后循序,听麻烦的。所以我就硬着头皮把观察者模式改了改。

调整后的观察者应用

抽象通知者类

''' <summary>
''' 抽象通知者
''' </summary>
''' <remarks></remarks>
Public MustInherit Class SubjectBll
    Public observers As IList(Of ObserverBll) = New List(Of ObserverBll)
    ''' <summary>
    ''' 添加观察者
    ''' </summary>
    ''' <param name="observer"></param>
    ''' <remarks></remarks>
    Public MustOverride Sub Attach(ByVal observer As ObserverBll)


    ''' <summary>
    ''' 去除观察者
    ''' </summary>
    ''' <param name="observer"></param>
    ''' <remarks></remarks>
    Public MustOverride Sub Detach(ByVal observer As ObserverBll)
    ''' <summary>
    ''' 通知观察者
    ''' </summary>
    ''' <param name="onOffLine"></param>
    ''' <remarks></remarks>
    Public MustOverride Function Notify(ByVal onOffLine As Entity.OnOffLineInfo)

End Class

抽象观察者类

''' <summary>
''' 抽象观察者
''' </summary>
''' <remarks></remarks>
Public MustInherit Class ObserverBll
    Public MustOverride Function Update(ByVal onOffLine As Entity.OnOffLineInfo)
End Class

具体观察者类 卡号是否存在并没有退卡

''' <summary>
''' 具体观察者 卡号是否存在并没有退卡,符合条件返回关于学生和卡的泛型
''' </summary>
''' <remarks></remarks>
Public Class IsExitCardNoBLL : Inherits BLL.ObserverBll

    Public Overrides Function Update(onOffLine As Entity.OnOffLineInfo)
        Dim Factory As New Factory.MyFactory
        Dim IFrmMainOnOffLine As IDAL.IFrmMainOnOffLine
        IFrmMainOnOffLine = Factory.CreateIFrmMainOnOffLine

        Dim myList As List(Of Entity.OnOffLineInfo)
        myList = IFrmMainOnOffLine.CheckCardInfo(onOffLine)
        Return myList


    End Function


End Class

具体观察者 检查是否正在上机

''' <summary>
''' 具体观察者 检查是否正在上机 返回布尔类型
''' </summary>
''' <remarks></remarks>
Public Class CheckOnOffLineState : Inherits BLL.ObserverBll

    Public Overrides Function Update(onOffLine As Entity.OnOffLineInfo) As Object
        Dim Factory As New Factory.MyFactory
        Dim IFrmMainOnOffLine As IDAL.IFrmMainOnOffLine
        IFrmMainOnOffLine = Factory.CreateIFrmMainOnOffLine

        Dim flag As Boolean
        flag = IFrmMainOnOffLine.CheckOnOffLineState(onOffLine)
        Return flag
    End Function
End Class

具体观察者类 添加上机记录

''' <summary>
''' 具体观察者 添加上机记录 返回的是布尔型
''' </summary>
''' <remarks></remarks>
Public Class AddOnOffLineRecord : Inherits BLL.ObserverBll

    Public Overrides Function Update(onOffLine As Entity.OnOffLineInfo) As Object
        Dim Factory As New Factory.MyFactory
        Dim IFrmMainOnOffLine As IDAL.IFrmMainOnOffLine
        IFrmMainOnOffLine = Factory.CreateIFrmMainOnOffLine

        Dim flag As Boolean
        flag = IFrmMainOnOffLine.AddOnOffLineRecord(onOffLine)
        Return flag
    End Function
End Class


在抽象通知者Update方法中没有定义返回值类型,所以具体通知者中默认返回类型是对象型。我没有使用全局变量,所以在具体通知者中对各具体观察者进行了逻辑判断。

具体通知者 上机

''' <summary>
''' 具体通知者 正常下机
''' </summary>
''' <remarks></remarks>
Public Class NormalOffLineSubject : Inherits SubjectBll


    Public Overrides Sub Attach(observer As ObserverBll)

    End Sub

    Public Overrides Sub Detach(observer As ObserverBll)

    End Sub
    '返回值是对象型的
    Public Overrides Function Notify(onOffLine As Entity.OnOffLineInfo) As Object
        Dim isExistCardNoObserver As New BLL.IsExitCardNoBLL
        Dim checkOnOffLineStateObserver As New BLL.CheckOnOffLineState
        Dim calculateMoney As New BLL.CalculateMoney

        Dim myList As List(Of Entity.OnOffLineInfo)
        myList = isExistCardNoObserver.Update(onOffLine) '如果卡号存在就把卡和学生的信息获得
        Dim onOffLineInfo As New Entity.OnOffLineInfo

        If IsNothing(myList) = False Then
            Dim flagState As Boolean
            flagState = checkOnOffLineStateObserver.Update(onOffLine)
            If flagState = True Then '卡正在上机


                Dim listOnOffLine As List(Of Entity.OnOffLineInfo)

                '把卡号传入算钱的类,算出消费时间和消费金额
                listOnOffLine = calculateMoney.CalculateConsumeCashAndBalance(onOffLine)

                '把消费的钱和下机时间的信息传给实体
                onOffLineInfo.cardID = listOnOffLine(0).cardID
                onOffLineInfo.consumeTime = listOnOffLine(0).consumeTime
                onOffLineInfo.consumeCash = listOnOffLine(0).consumeCash
                onOffLineInfo.balance = listOnOffLine(0).balance
                onOffLineInfo.offLineDate = Format(Today(), "yyyy-MM-dd").ToString
                onOffLineInfo.offLineTime = Format(TimeOfDay(), "HH:mm:ss").ToString

                '调用接口层修改上下机表的函数接口
                Dim Factory As New Factory.MyFactory
                Dim IFrmMainOnOffLine As IDAL.IFrmMainOnOffLine
                Dim flagAlter As Boolean
                IFrmMainOnOffLine = Factory.CreateIFrmMainOnOffLine
                flagAlter = IFrmMainOnOffLine.AlterOnOffLineRecord(onOffLineInfo)

                If flagAlter = True Then
                    '如果修改成功,调用返回上下机信息的接口,并把前面得到的学生和卡的信息也传给该泛型
                    listOnOffLine = IFrmMainOnOffLine.ReturnOnOffLineRecord(onOffLine)
                    listOnOffLine(0).studentID = myList(0).studentID
                    listOnOffLine(0).name = myList(0).name
                    listOnOffLine(0).type = myList(0).type
                    Return listOnOffLine
                Else
                    Return flagAlter
                End If

            Else
                Return flagState
            End If
        Else
            Return Nothing
        End If
    End Function
End Class


所以,在客户端调用具体通知者上机的时候,就要对它的返回值进行判断,他返回的是object型,但到底是list还是Boolean,就需要判断了。

U层 单击上机按钮触发的事件

'单击上机按钮
    Private Sub btnOnLine_Click(sender As Object, e As EventArgs) Handles btnOnLine.Click
        If txtCardID.Text = "" Then
            MsgBox("卡号不能为空", MsgBoxStyle.Exclamation, "提示")
            Exit Sub
        End If

        Dim onOffLine As New Entity.OnOffLineInfo
        onOffLine.cardID = txtCardID.Text

        Dim Facade As New Facade.FrmOnLineSubjectFacade
        Dim myObject As Object

        myObject = Facade.Notify(onOffLine)'用对象类型接收



        If myObject Is Nothing Then
            MsgBox("此卡号不存在,或已退卡", MsgBoxStyle.Exclamation, "提示")
            Exit Sub
        End If
        If myObject.ToString = "False" Then  '判断对象类型是不是false
            MsgBox("上机失败,更新记录失败", MsgBoxStyle.Exclamation, "提示")
            Exit Sub
        End If

        If myObject.ToString = "True" Then
            MsgBox("该卡号正在上机", MsgBoxStyle.Exclamation, "提示")
            Exit Sub
        End If

        '如果返回值既不是false也不是true,那就是泛型了
        Dim myList As New List(Of Entity.OnOffLineInfo)
        myList = CType(myObject, List(Of Entity.OnOffLineInfo)) '把对象类型的值转换成泛型

        If myList(0).type.Trim() = "临时用户" Then
            GroupBox1.Visible = False
        Else
            GroupBox1.Visible = True
        End If

        lblType.Text = myList(0).type
        lblStudentID.Text = myList(0).studentID
        lblName.Text = myList(0).name
        lblBalance.Text = myList(0).balance
        lblOnLineDate.Text = Format(Today(), "yyyy-MM-dd")
        lblOnLineTime.Text = TimeOfDay()

        '一个号上机后,实时更新消费时间,消费金额和余额
        timerInstantUpdate.Enabled = True
    End Sub

小结


实现上下机功能有两个感触。一、现在处于学习阶段,尽量尝试使用模式是好的,去体会模式的特点和优缺点,但是如果在真正做项目的时候就要使用适当的模式。合作的时候上下机我打算使用职责链模式,这次因为在算时间的时候用了职责链所以上下机用的观察者。二、在不知道怎么做的时候,去做就行了,想要实现什么功能就想法去实现,模式是前人总结出来的在某种情况下比较适合使用的方法,但并不是一成不变的,发挥想象力,根据需求适当改变也是可以的。

We are building something new, which is the most exciting thing we have ever had.

你可能感兴趣的:(机房重构——观察者模式上下机)