机房收费系统重构之策略模式

一、前言

前面我们学习了23种设计模式,不过一直没用过,这次机房重构就是让我们将学习的这些理论应用与实践。首先,机房收费的主要功能就是上机收费,一说的收费就会有针对普通用户和会员等,实行不同的收费方法,这时我们就需要用到策略模式了。

二、回顾

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

详见:设计模式
( 十八 ) 策略模式Strategy(对象行为型)

三、代码实现(为了方便,将整个下机过程的代码全部给出)

1、U层中下机按钮的代码

    ''' <summary>
    ''' 下机功能
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click

        Dim facadeSystem As New FacadeSystem
        Dim cardEntity As New CardEntity

        Try
            cardEntity.CardId = txtCardId.Text            '传参

            Dim returnOnList As ArrayList

            '调用外观,实现下机
            returnOnList = facadeSystem.StudentOff(cardEntity)

            '提出返回的数据
            Dim returnStudentEntity As StudentEntity
            Dim returnLineRecordEntity As LineRecordEntity
            Dim returnCardEntity As CardEntity

            returnStudentEntity = returnOnList.Item(0)
            returnLineRecordEntity = returnOnList.Item(1)
            returnCardEntity = returnOnList.Item(2)

            '显示学生信息
            txtStudentId.Text = returnStudentEntity.StudentId
            txtName.Text = returnStudentEntity.StudentName
            txtSex.Text = returnStudentEntity.Sex
            txtClass.Text = returnStudentEntity.Classes
            txtDepartment.Text = returnStudentEntity.Department
            txtExplan.Text = returnStudentEntity.Explain
            txtGrade.Text = returnStudentEntity.Grade
            '显示上机信息
            txtOnTime.Text = returnLineRecordEntity.OnTime
            txtOffTime.Text = returnLineRecordEntity.OffTime
            txtConsumeCash.Text = returnLineRecordEntity.ConsumeCash
            txtConsumeTime.Text = returnLineRecordEntity.ConsumeTime
            txtRemainCash.Text = returnCardEntity.RemainCash

            '显示上机人数
            lbOnPeople.Text = facadeSystem.RefreshOnPeople()

            '显示上机成功
            lbInformation.Text = "欢迎下次光临!"

        Catch ex As Exception
            MsgBox(ex.Message)
        End Try

    End Sub

2、外观层代码

		''' <summary>
		''' 学生下机
		''' </summary>
        Public Function StudentOff(ByVal cardEntity As CardEntity) As ArrayList
            Try
                Dim cardBLL As New CardBLL
                Dim returnCardEntity As New CardEntity
                Dim returnBoolean As Boolean

                '检查卡号是否存在
                returnBoolean = cardBLL.QueryCard(cardEntity)
                If Not returnBoolean Then
                    Throw New Exception("卡号不存在!")
                End If

                '检查该卡号是否正在上机
                Dim lineRecordBll As New LineRecordBLL

                returnBoolean = lineRecordBll.GetOffStatus(cardEntity)
                If Not returnBoolean Then
                    Throw New Exception("该卡号还没上机!")
                End If

                '如果正在上机,就查到上机信息
                Dim lineRecordEntity As New LineRecordEntity

                lineRecordEntity = lineRecordBll.GetOff(cardEntity)

                '查看基础数据设定
                Dim basicDataEntity As New BasicDataEntity
                Dim basicDataBll As New BasicDataBLL

                basicDataEntity = basicDataBll.QueryAll()

                '计算消费时间
                Dim getDateBll As New GetDateBLL
                Dim strPrepareTime As Double
                Dim consumeTime As Double

                lineRecordEntity.OffTime = getDateBll.GetSqlTime()                                                                      '获取下机时间

                strPrepareTime = getDateBll.changeForHour(basicDataEntity.PrepareTime)                                                  '将准备时间转换为以小时为单位
                consumeTime = getDateBll.TimeToHour(lineRecordEntity.OffTime) - getDateBll.TimeToHour(lineRecordEntity.OnTime)          '计算消费时间

                '判断消费时间是否大于准备时间
                If consumeTime < strPrepareTime Then
                    lineRecordEntity.ConsumeTime = "0.0"
                Else
                    lineRecordEntity.ConsumeTime = CStr(consumeTime - strPrepareTime)
                End If

                '计算消费金额
                Dim strStudentLevel As String = "GeneralUser"   '用来实例化具体的计费方法
                Dim cashContext As CashContext

                cashContext = New CashContext(strStudentLevel)   '实例化计费方法的类
                lineRecordEntity.ConsumeCash = CStr(cashContext.GetResult(basicDataEntity, lineRecordEntity))

                '其他参数
                lineRecordEntity.OffDate = getDateBll.GetSqlDate()
                lineRecordEntity.OffStatus = "正常下机"
                lineRecordEntity.Local = System.Net.Dns.GetHostName().ToString

                '记录为正常下机
                lineRecordBll.AddOff(lineRecordEntity)

                '修改卡上余额
                cardEntity = cardBLL.QueryAll(cardEntity)
                cardEntity.RemainCash = CStr(CDbl(cardEntity.RemainCash) - CDbl(lineRecordEntity.ConsumeCash))

                cardBLL.ModifyRemainCash(cardEntity)

                '查询学生实体
                Dim studentEntity As New StudentEntity
                Dim studentBll As New StudentBLL

                studentEntity.StudentId = cardEntity.CardId
                studentEntity = studentBll.QueryAll(studentEntity)

                '封装,传回
                Dim returnOnList As New ArrayList

                returnOnList.Add(studentEntity)
                returnOnList.Add(lineRecordEntity)
                returnOnList.Add(cardEntity)

                Return returnOnList

            Catch ex As Exception
                Throw
            End Try

        End Function

3、cashContent类(相当于策略模式图中的Context类

''' <summary>
	''' 策略模式中的context类,用一个具体计费方法来配置,维护一个对抽象计费方法对象的引用
	''' </summary>
	Public Class CashContext

		''' <summary>
		''' 声明一个计算消费金额的抽象类
		''' </summary>
        Private cashSuper_ As CashSuper
        Private _strStudentLevel As String

		''' <summary>
		''' 声明一个计算消费金额的抽象类
		''' </summary>
		Private Property cashSuper() As CashSuper
			Get
                Return cashSuper_
			End Get
			Set(ByVal Value as CashSuper)
                cashSuper_ = Value
			End Set
		End Property

		''' <summary>
		''' 通过构造方法,传入具体的收费策略
		''' </summary>
        ''' <param name="strStudentLevel">初始化时,传入一个具体的收费策略</param>

        Sub New(strStudentLevel As String)

            Try
                '利用反射创建具体的算法
                Dim AssemblyName As String = "BLL"
                Dim className As String = AssemblyName + ".BLL." + strStudentLevel + "ConsumeCash"

                Me.cashSuper_ = CType(Assembly.Load(AssemblyName).CreateInstance(className), CashSuper)

            Catch ex As Exception
                Throw
            End Try

        End Sub

        ''' <summary>
        ''' 根据不同的收费策略,获得计算结果
        ''' </summary>
        ''' <param name="basicDataEntity"></param>
        ''' <param name="lineRecordEntity"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetResult(ByVal basicDataEntity As BasicDataEntity, ByVal lineRecordEntity As LineRecordEntity) As Double

            Try
                Dim returnDouble As Double
                returnDouble = cashSuper_.CountConsumeCash(basicDataEntity, lineRecordEntity)

                Return returnDouble

            Catch ex As Exception
                Throw
            End Try

        End Function

	End Class ' CashContext

4、CashSuper抽象类(相相当于策略模式图中的Strategy类

	''' <summary>
    ''' 策略模式,封装计算方法的抽象类
	''' </summary>
    Public MustInherit Class CashSuper

        ''' <summary>
        ''' 计算消费金额的计算方法
        ''' </summary>
        ''' <param name="lineRecordEntity">上机记录表的实体</param>
        ''' <param name="basicDataEntity">数据库数据表实体</param>
        Public MustOverride Function CountConsumeCash(ByVal basicDataEntity As BasicDataEntity, ByVal lineRecordEntity As LineRecordEntity) As Double

    End Class ' CashSuper

5、GeneralUserConsumeCash类(相相当于策略模式图中的CreateStrategy类,具体收费方法

	''' <summary>
	''' 计算一般用户消费的方法
	''' </summary>
	Public Class GeneralUserConsumeCash
		Inherits BLL.CashSuper

	''' <summary>
	''' 计算消费金额的计算方法
	''' </summary>
        ''' <param name="lineRecordEntity">上机记录表的实体</param>
        ''' <param name="basicDataEntity">数据库数据表实体</param>
        Public Overrides Function CountConsumeCash(ByVal basicDataEntity As BasicDataEntity, ByVal lineRecordEntity As LineRecordEntity) As Double

            Try
                Dim returnMoney As Double
                Dim countTime As Integer           '表示多少个单位时间
                Dim oneMinuteMoney As Double       '每分钟消费的钱

                oneMinuteMoney = CDbl(basicDataEntity.UnitCash) / 60

                '判断是否在规定上机时间内
                If lineRecordEntity.ConsumeTime > basicDataEntity.LeastTime Then         '如果超过至少上机时间
                    '单位时间的个数=(消费时间-至少上机时间)/单位时间
                    countTime = CInt(Int((CDbl(Minute(CDate(lineRecordEntity.ConsumeTime))) - CDbl(basicDataEntity.LeastTime)) / basicDataEntity.UnitTime + 0.9999))
                    '消费金额=(单位时间个数*单位时间+至少上机时间)*每分钟消费的钱
                    returnMoney = (countTime * basicDataEntity.UnitTime + CDbl(basicDataEntity.LeastTime)) * oneMinuteMoney
                    Return returnMoney
                Else                                                                     '如果没有超过至少上机时间
                    '至少上机时间乘以单位时间的钱
                    returnMoney = CDbl(basicDataEntity.LeastTime) * oneMinuteMoney
                    Return returnMoney
                End If

            Catch ex As Exception
                Throw
            End Try

        End Function

	End Class ' GeneralUserConsumeCash

四、解说执行过程

首先,将 "GeneralUser"传给变量strStudentLevel,作用是在Dim className As String = AssemblyName + ".BLL." + strStudentLevel + "ConsumeCash"这句话中,利用反射创建具体的收费方法,即普通用户的收费方法GeneralUserConsumeCash类。

然后,调用cashContext.GetResult()方法,此方法又调用抽象类cashSuper的计算消费金额CountConsumeCash

的方法,由于此方法在子类中被重写,所以最后执行具体收费类GeneralUserConsumeCash的CountConsumeCash方法,从而得出结果。

五、总结

本来可以通过访问配置文件向cashContext中传入参数,从而判断具体的收费方法,这样当我们需要修改收费方法的时候直接修改配置文件就行了,使我们的维护更加的方便。由于这次只使用了普通用户,所以计费方法只有一种,仅仅采用的strStudentLevel变量传参,大大降低了系统的可维护性。所以在以后,我们做系统的时候一定要注意,尽量减少系统的耦合度,从而创造出更加优秀的产品。

时间: 2024-10-13 19:13:22

机房收费系统重构之策略模式的相关文章

机房收费系统重构——数据库设计

终于,走到了机房收费系统重构的阶段-- 之前的一遍机房收费系统的数据库是用的给的那个,只是把每个表都看了一下,当时也没有学习数据库原理那本书,然后就没有深究-- 现在不一样了,我们进行机房收费系统重构,况且学习了数据库原理这本书,对数据库有了更深的认识.所以对于数据库要好好的设计,按照步骤走-- 数据库技术是信息资源管理最有效地手段.数据库设计是指对于一个给定的应用环境,构造最优的数据库模式,建立数据库及其应用系统,有效存储数据,满足用户信息要求和处理要求. 数据库的设计的步骤和各阶段的主要内容

vb.net机房收费系统重构——总结(二)软件工程文档1

学软工时常常听到:这是我们迈向职业化的一步.软件工程文档在一个项目开发中必不可少,通过这次重构,将以前的软件工程,UML重新认识,梳理,实用了一遍有了更深刻的体会,我在机房重构中,一共编写了七个文档,分别是 1.项目开发计划 2.软件需求说明书 3.数据库设计说明书 4.概要设计说明书 5.详细设计说明书 6.机房收费系统测试计划 7.机房收费系统用户操作手册 在这里只讲一下项目开发文档中各种需要的图.表. (一)软件项目开发计划: 文档的目的不用说,在这里面最重要的两个内容:项目的人员分工,以

vb.net版机房收费系统重构

机房收费系统重构版终于正式开工了! 前几天,刚刚看完三层的视频,在视频中详细的讲解了一个登录功能.天真的我,当时以为三层结构是那么的简单,所以我草草地做完总结之后,就很快就开始机房收费系统的重构了.可是谁想到,当我一打开编程软件,就让我"碰了一鼻子的灰"!首先是不知道vs 怎么用,其次就是看三层的时候,登录的实例使用C#写的,而这次我们需要用VB.NET写,所以对于其中的语法是知之甚少.虽然,前段时间我看了一遍台湾讲师--曹祖胜的<VB.NET 视频>,但是他讲的几乎都是一

机房收费系统重构(六)—泛型集合

      机房收费系统重构仍在进行,但是在进行过程中,也许数据类型的转换是永远也避不开的,今天我就来讲讲关于数据类型转换的问题!       在个人版机房收费系统中,在DAL层中,如果是增删改,是不需要返回参数的,返回值是Boolean,但是在查询中,需要有返回值,而且返回的是Dateset类型,所以在这里问题就来了.      如果在返回值过程中一直返回的是表的类型,也许就没有那么多麻烦的事情了,但是dateset使得系统具有了强耦合性,但是如果返回的是实体类呢!关于这点我也查了查资料,为什

机房收费系统重构(三)

前段时间用简单的三层实现了窗体登录功能,心中有点小小的成就感,但是很快就被泼了凉水,机房收费不可能只用三层实现,如果你用三层,也就是说后面机房收费所有的功能都必须使用三层来实现功能.所以一周前始了七层的研究.经过一个星期的看博客,总结,调代码,终于实现了窗体登录,信息录入,和简单充值查询功能.   说说自己这次七层之旅的总结吧.   1.毋庸置疑,研究一个窗体功能,我首先判断的是需要用到数据库中的哪些表(这是属于我自己的编程习惯,不适用全部),然后再实体层中将表中的字段表示出来,有多少个表就有多

机房收费系统重构(五)—登陆窗口完整版

     在上上篇.<机房收费系统重构(3)>.中主要是介绍了自己关于DAL层,工厂层.以及接口层,还有实体层的理解.可是好多读者再问我.你的代码呢,我在这解释一下.就是我仅仅是写出关于那几部分的理解,并没有写贴出代码让大家研究的.可是不能顺应民心的文章不是好文章,所以我在这篇文章中,将机房收费登录中七层中全部的代码,贴出来供大家拍砖斧正.还有最后我在谈谈针对BLL层和外观层的理解.      首先我所说的七层是针对UI层,外观层,BLL层,DAL层,工厂层,实体层,接口层七层组成.    

机房收费系统重构(五)

     在上上篇,<机房收费系统重构(3)>,中主要是介绍了自己关于DAL层,工厂层,以及接口层,还有实体层的理解,但是好多读者再问我,你的代码呢,我在这解释一下,就是我只是写出关于那几部分的理解,并没有写贴出代码让大家研究的,但是不能顺应民心的文章不是好文章,所以我在这篇文章中,将机房收费登录中七层中所有的代码,贴出来供大家拍砖斧正,还有最后我在谈谈针对BLL层和外观层的理解.      首先我所说的七层是针对UI层,外观层,BLL层,DAL层,工厂层,实体层,接口层七层组成.      

机房收费系统重构初期问题总结

进入五月份開始的三层架构的学习.那个时候,三层仅仅是理解了一些理论知识.还有在师父验收三层登陆实例的时候,仅仅知道三层是怎样建立起来的. 并且在验收的过程中,发现非常多逻辑性的错误.三层结束到机房重构,之间不知道停顿了多久.总之,真正開始重构的也就一个星期左右. 在三层结束之后,就要谋划机房重构的问题了. 可是,对于已经学习了非常多理论知识之后.发现,对于要開始重构机房一点思路都没有.不知道是先从哪里下手,文档?UML图?程序?这样的感觉真是-- 查看tgb的培养计划.从让导师指导建模開始. 也

vb.net版机房收费系统重构的成长历程(功能实现篇)

重构机房收费系统,功能是不变的,需求是不变的,系统背后的代码,架构发生了改变.做过vb6.0版的系统 后,利用VS的VB.NET平台, 通过调整程序架构,加入了设计模式,改善软件的质量.性能,提高软件的扩展性和维护性.相比旧版系统,新版系统主要亮点有: 亮点一:代码分层管理,清晰明了 亮点二:加入工厂和接口,代码复用较多,减少了重复或相似的代码. 亮点三:用到了存储过程.一方面减少了代码量,另一方面也相当于是一个事务的执行.比如注册或者结账需要同 时操作多张表,这几个表必须同时被操作成功后才可以