上下机折腾了好几天,本着学习的目的用的是观察者模式。深刻的感受到上下机不适合用观察者。但是如果非要使,也不是不可以~~
上下机使用观察者的问题分析
观察者模式在客户端实例化一个具体的通知者,具体通知者中加上具体的观察者,然后使用具体通知者的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.