重构机房收费系统之 模板方法模式

            对于模板方法模式的使用,我后悔自己用晚了,因为我们的机房收费收费系统有很多窗体是几乎一样的,如果我们不用模板方法模式,就会大大增加工作量,首先,我们需要重复的创建窗体,其次我们的代码量也会大大增加,就是复制、粘贴代码也是一件让人摒弃的事情,所以推出模板方法模式,用意就在降低代码重复,减少工作量,通过求同存异的思想来实现。下面看一下我在组合查询中用到的模板方法模式:

          首先,创建父窗体,父窗体的创建就是普通的winform,我们知道组合查询这块儿一共有四个窗体是大同小异的:学生上机状态查看、上机信息统计、学生基本信息维护、操作员工作记录,他们的窗体(包括控件)是一致的,除字段名和要查询的内容不一样,其余都一样,所以要用到重写,在每个子窗体中根据本窗体的需要而有所不同:下面看一下父窗体的代码:        

Imports Entity
Imports Facade
Public Class frnMulSelection
    Protected enMulSelection As New MulSelectionEntity
    ''' <summary>
    ''' 查询
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub btnQuery_Click(sender As Object, e As EventArgs) Handles btnQuery.Click
        Try
            '如果第一个连接条件为空
            If cboConnection1.Text.Trim = "" Then
                Dim arrayControl() As Control
                ReDim Preserve arrayControl(2)

                arrayControl(0) = cboFields1
                arrayControl(1) = cboOperator1
                arrayControl(2) = txtContent1
                '判断第一行是否为空
                If IsSomeEmptyText(arrayControl) = True Then
                    Exit Sub
                End If
                SelectData()
            Else
                If cboConnection2.Text.Trim = "" Then
                    Dim arrayControl() As Control
                    ReDim Preserve arrayControl(6)

                    arrayControl(0) = cboFields1
                    arrayControl(1) = cboOperator1
                    arrayControl(2) = txtContent1
                    arrayControl(3) = cboConnection1
                    arrayControl(4) = cboFields2
                    arrayControl(5) = cboOperator2
                    arrayControl(6) = txtContent2
                    '判断第一行是否为空
                    If IsSomeEmptyText(arrayControl) = False Then
                        Exit Sub
                    End If
                Else
                    '如果关系1和2都不为空,判断控件内容是否为空
                    If IsAllEmptyText(Me) = False Then
                        Exit Sub
                    End If
                End If
            End If
        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Exclamation, "提示")
        End Try
    End Sub
    ''' <summary>
    ''' 字段名
    ''' </summary>
    ''' <param name="getFields"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>

    Public Overridable Function sqlFields(ByVal getFields As String) As String
        Return ""
    End Function

    ''' <summary>
    ''' 获取表名
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overridable Function GetTable() As String
        Return ""
    End Function

    ''' <summary>
    ''' 拼接字符串
    ''' </summary>
    ''' <param name="frm"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Query(frm As frnMulSelection) As String
        Dim strConnection As String '拼接字符串
        '如果第一个链接条件为空
        If frm.cboConnection1.Text = "" Then
            strConnection = " " & sqlFields(frm.cboFields1.Text) & frm.cboOperator1.Text & " '" & frm.txtContent1.Text & "'"
        Else
            '如果第一个不为空,第二个为空
            If Me.cboConnection2.Text = "" Then
                strConnection = " " & sqlFields(Me.cboFields1.Text) & Me.cboOperator1.Text & " '" & Me.txtContent1.Text & "'" &
                    sqlFields(Me.cboConnection1.Text) & " " & sqlFields(Me.cboFields2.Text) & Me.cboOperator2.Text & "'" & Me.txtContent2.Text & "'"
            Else
                '如果两个链接条件都不为空
                strConnection = " " & sqlFields(Me.cboFields1.Text) & Me.cboOperator1.Text & " '" & Me.txtContent1.Text & "'" &
                    sqlFields(Me.cboConnection1.Text) & " " & sqlFields(Me.cboFields2.Text) & Me.cboOperator2.Text & "'" & Me.txtContent2.Text & "'" &
                    sqlFields(Me.cboConnection2.Text) & " " & sqlFields(Me.cboFields3.Text) & Me.cboOperator3.Text & "'" & Me.txtContent3.Text & "'"
            End If
        End If
        Return strConnection
    End Function
    ''' <summary>
    ''' 执行查询的关键函数
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Protected Overridable Function SelectData()
        Return ""
    End Function

    ''' <summary>
    ''' 退出
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
        Me.Dispose()
    End Sub

    Private Sub frnMulSelection_Load(sender As Object, e As EventArgs) Handles Me.Load
        '将每个表共同的操作符提取出来
        btnMofify.Visible = False
        cboOperator1.Items.Add("=")
        cboOperator1.Items.Add("<")
        cboOperator1.Items.Add(">")
        cboOperator1.Items.Add("<>")

        cboOperator2.Items.Add("=")
        cboOperator2.Items.Add("<")
        cboOperator2.Items.Add(">")
        cboOperator2.Items.Add("<>")

        cboOperator3.Items.Add("=")
        cboOperator3.Items.Add("<")
        cboOperator3.Items.Add(">")
        cboOperator3.Items.Add("<>")

        'cboConnection1.SelectedIndex = 1
        cboConnection1.Items.Add("")
        cboConnection1.Items.Add("与")
        cboConnection1.Items.Add("或")
        'cboConnection2.SelectedIndex = 1
        cboConnection2.Items.Add("")
        cboConnection2.Items.Add("与")
        cboConnection2.Items.Add("或")
        '在父窗体中填充选项
        enMulSelection.Fields1 = "1"
        enMulSelection.Fields2 = "1"
        enMulSelection.Fields3 = "1"
        enMulSelection.Operator1 = "="
        enMulSelection.Operator2 = "="
        enMulSelection.Operator3 = "="
        enMulSelection.Content1 = "1"
        enMulSelection.Content2 = "1"
        enMulSelection.Content3 = "1"
        enMulSelection.Connection1 = "and"
        enMulSelection.Connection2 = "and"
        '在一开始的时候,只允许第一个条件行可用,只有选择了连接关系后,其他下面的条件行在可以用
        cboFields2.Enabled = False
        cboOperator2.Enabled = False
        txtContent2.Enabled = False
        cboConnection2.Enabled = False
        cboFields3.Enabled = False
        cboOperator3.Enabled = False
        txtContent3.Enabled = False

    End Sub
    ''' <summary>
    ''' 如果选择了第一个连接调节,则第二个条件行也可以写入
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub cboConnection1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboConnection1.SelectedIndexChanged
        cboFields2.Enabled = True
        cboOperator2.Enabled = True
        txtContent2.Enabled = True
        cboConnection2.Enabled = True
    End Sub
    ''' <summary>
    ''' 同上
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub cboConnection2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboConnection2.SelectedIndexChanged
        cboFields3.Enabled = True
        cboOperator3.Enabled = True
        txtContent3.Enabled = True

    End Sub
    ''' <summary>
    '''用于学生信息维护中的修改学生信息时选中某行修改,是虚函数
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Public Overridable Sub DataGridView1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick

    End Sub
End Class

          子窗体是这样继承的:

          

         点击“添加”后,选择要继承的父窗体:

         

          下面是子窗体的代码:         

Imports Facade '导入外观
Imports Entity '导入实体
Public Class frmMulWorkLog
    Private Sub frmMulWorkLog_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        cboFields1.Items.Add("教师")
        cboFields1.Items.Add("注册日期")
        cboFields1.Items.Add("注册时间")
        cboFields1.Items.Add("注销日期")
        cboFields1.Items.Add("注销时间")
        cboFields1.Items.Add("机器号")

        cboFields2.Items.Add("教师")
        cboFields2.Items.Add("注册日期")
        cboFields2.Items.Add("注册时间")
        cboFields2.Items.Add("注销日期")
        cboFields2.Items.Add("注销时间")
        cboFields2.Items.Add("机器号")

        cboFields3.Items.Add("教师")
        cboFields3.Items.Add("注册日期")
        cboFields3.Items.Add("注册时间")
        cboFields3.Items.Add("注销日期")
        cboFields3.Items.Add("注销时间")
        cboFields3.Items.Add("机器号")

    End Sub
    Protected Overrides Function SelectData() As Object

        Dim facWorkLog As New WorkLogFacade
        Dim dtWorkLog As New DataTable
        Dim frmmulworklog As New frmMulWorkLog

        Dim strConnection As String
        strConnection = frmmulworklog.Query(Me) '此处用到了多态,把子类传给父类,重写父类的方法。

        Try
            dtWorkLog = facWorkLog.SelectMulWork(strConnection)
            If dtWorkLog.Rows.Count <= 0 Then
                dtWorkLog.Clear() '清空datatable中上次的记录
                DataGridView1.DataSource = Nothing '使表中的数据为空
                DataGridView1.Refresh() '重新绘制表
            Else
                DataGridView1.DataSource = dtWorkLog
                DataGridView1.Columns(0).Visible = False
                DataGridView1.Columns(0).HeaderText = "序列号"
                DataGridView1.Columns(1).HeaderText = "教师"
                DataGridView1.Columns(2).Visible = False
                DataGridView1.Columns(2).HeaderText = "用户级别"
                DataGridView1.Columns(3).HeaderText = "注册日期"
                DataGridView1.Columns(4).HeaderText = "注册时间"
                DataGridView1.Columns(5).HeaderText = "注销日期"
                DataGridView1.Columns(6).HeaderText = "注销时间"
                DataGridView1.Columns(7).HeaderText = "机器号"
            End If

        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Exclamation, "提示")
        End Try

    End Function
    Public Overrides Function sqlFields(getFields As String) As String

        Select Case getFields
            Case "序列号"
                Return "serious"
            Case "教师"
                Return "UserName"
            Case "用户级别"
                Return "UserLevel"
            Case "注册日期"
                Return "LogOnDate"
            Case "注册时间"
                Return "LogOnTime"
            Case "注销日期"
                Return "LogOffDate"
            Case "注销时间"
                Return "LogOffTime"
            Case "机器号"
                Return "机器号"
            Case "或"
                Return "Or"
            Case "与"
                Return "And"
            Case Else
                Return ""
        End Select

    End Function
    Public Overrides Function GetTable() As String
        enMulSelection.Table = "T_WorkLog"
        Return "T_WorkLog"
    End Function
End Class

           子窗体的代码很简单,就是对不同的地方进行了重写,其他的只需要继承父窗体就可以了,至于外观层、B层、D层与其他窗体都是一样的,在这里就不一一列出了。

            设计模式学了很多种模式,可是真正去想的时候,也只是知道有这么个模式,至于怎么用,不知道,只有在敲机房的时候,使劲的加,才能体会到它的好处与不足,让知识活了起来!

         

时间: 2024-09-09 22:57:10

重构机房收费系统之 模板方法模式的相关文章

机房收费系统重构中的一些感受

        在正式写文章之前反省一下,好久没有到CSDN上来写博客了,也就是说自己已经有一段时间学习劲头不足了.今天写这篇文章一方面是总结一下自己这半个月敲机房收费系统的一点点小的体会,另一方面就是写写刚刚实现的"运用简单工厂实现登陆权限选择"的实例.         其实重构机房收费系统这各项目已经建立两个月了,只是前一个半月由于一些未知的原因导致自己心里例假而什么都没有干.半个月前,借着家长过来的机会,米老师顺便把我的情况提了一下,顿时感觉愧疚难当,同时一股强烈的查克拉在我体内

机房收费系统:(一)窗体模式 frmLogin.Show vbModal

 一.窗体模式区别     窗体分为模式的和非模式的.    模式的:用户只能使用当前窗体,只有当前窗体关闭后其他窗体才可用:可以这样理解,如果你把某个窗体设为模式窗体,那么你要想对其它窗体进行任何操作之前,必须先关闭该窗体.模式窗体强迫用户输入数据,不能切换到其他界面,很多地方会用到,比如在浏览器里点文件--打开,还有打印对话框也是模式窗体.有的模式窗口或称模态窗口,Msgbox.Inputbox产生的窗口也属于此类.     非模式的:不必关闭该窗体,就可转换到其它窗体上进行操作.   二.

机房收费系统个人重构关于SQLHelper

              最近在敲机房,对于SQLHelper也是心里有些怵,因为原来没用过,但是看了一些博客和资料后发现,如果不用这个类,会大大增加代码量,而且,其实它并不新,它是一个有多个关于数据库增删改查操作的语句函数的类,使用这个类可以方便D层调用,对数据库的操作,我们无非就是增删改查,而函数就是有无参数,有无返回值,SQLHelper是个新词,不过我们却一直在用,只是我们不这么叫,之所以叫SQLHelper,理所当然它是D层操作数据的助手,          在SQLHelper类中

机房收费系统(VB.NET)个人版总结

    重构版个人机房收费系统大概从暑假开学开始进行,花了不到一个半月的时间才完成,下面对我在重构过程中的一写理解.          1.系统设计一个很重要的目的就是重用,而要做到重用,低耦合是最有效的手段回顾一下我们C/S的整个学习过程,我们可以发现,从开始的VB版的机房收费系统,然后到现在VB.NET版,加设计模式.对系统进行分层,这个过程就是在对系统进行解耦.要解耦,首先就要进行抽象.把多次.重复用到的代码进行封装,其余的部分运用继承或者多态的思想,来进行使用.    在机房收费系统中我

视图——机房收费系统

 1.什么是视图?   在第一次做机房收费系统时,学生信息和卡的信息是在同一张表中的,而机房收费系统重构时,对数据库进行了重新设计,学生信息和卡的信息被分到了单独的两张表中(遵照三范式设计,减少数据冗余),当我们需要同时查询这两张表中的信息时,按照一般的方法从每张表中单独查询的话会非常麻烦且容易出错,为了减少出错,我们可以把要查询的信息整合到一张虚拟表中,这张虚拟表就是视图.   视图就如同一张表一样,对表能够进行的一般操作(增删改查)都可以应用于视图,一个视图是由SELECT语句组成的查询定义

VB.NET版机房收费系统---外观层如何写

       外观设计模式,<大话设计模式>第103页详细讲解,不记得这块知识的小伙伴可以翻阅翻阅,看过设计模式,敲过书上的例子,只是学习的第一步,接着,如果在我们的项目中灵活应用,把设计模式用出花儿来,才是王道,有人总说,纸上得来终觉浅,绝知此事要躬行,可是真到了躬行的时候,总是行不通,语言倒不过来,设计模式是C#语言的,机房收费是VB.NET版本的,书上的模式和机房联系不起来,不知道怎么应用,没办法,憋呗,看博客,问人,上网查资料,就这样,憋出一个外观,虽不太完美,但却异常宝贵,因为那是我

小结:VB.NET机房收费系统个人版

      经过几天的缝缝补补,自己的个人版终于OK了,!也许是因为有第一次的机房收费系统的经验,这次做,感觉非常亲切.      在业务逻辑方面,沿袭以前的逻辑,做了一点升级,但是改动不大.      在数据库方面,感觉自己从一个小菜鸟在成长.第一次做机房的时候,在数据库方面,只会"insert ,delete ,update, select",基本上是靠着四句话完成整个机房收费系统的.但是,这次在做的时候,用上了视图和存储过程和一些数据库中的小技巧.在表结构上也比以前简练了不少,靠

机房收费系统:(三)SQLSever中自增长ID问题

       在本次机房收费系统中,数据库的用户增加过程中需要将每个增加的用户给一个自增长的序列号,这就考虑到数据库和VB的交互过程,甚至我们会遇到在写数据库程序的时候,经常会需要获取某个表中的最大序号数,查询资料找了几个方法,解决问题. 一般情况下获取刚插入的数据的id,使用select max(id) from table 是可以的.但在多线程情况下,就不行了. (1) getGeneratedKeys()方法:      程序片断:         Connection conn=...;

机房收费系统注册之实时错误

         机房收费系统,按着既定的脚步一步一步的往前走,窗体布局,实现代码,调代码,一不小心,写错一个单词,或者定义出了问题,都会导致程序无法正常运行下去,导致错误的原因有很多,但是导致同一个错误的原因却又不尽相同,无论怎样,自己还是在一个有一个的bug中找到闪光点,一点一点的向前进......,下面的这些错误时在注册的时候遇到的,做一个简单的总结.          实时错误'-2147217873(80040e2f)'                  NULL,本意是空的,元素只有