重构个人版机房收费系统——模板模式

1、背景


在开始本篇博文之前,我们先来看一下下面截取的几幅图片:

1、组合查询

       重构个人版机房收费系统——模板模式_第1张图片    


  2、根据卡号查询记录并导出到Excel表格

         重构个人版机房收费系统——模板模式_第2张图片


3、按照指定的时间范围查询记录

重构个人版机房收费系统——模板模式_第3张图片


        是的,放眼望去,如果除去要实现的功能只考虑这三组图片的外观,那么每组的两张图片简直就是一个用模子刻出来的嘛~~~~~这就涉及到博文的主题了——模板模式。

2、模板模式

1、什么是模板模式

      模板模式,提供了一个代码复用平台,当不变和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现,形成了代码冗余,而且不易于维护,而模板模式就是把这些不变行为搬移到单一的地方(即超类),然后通过多态实现代码的复用。


2、机房收费实例讲解

      有了模板模式,最直观的一点好处就是再也不用花费很多时间在设置窗体界面上了(特别是组合查询),只要做个模子,直接“刻”就行啦~~。接下来就通过一个实例:学生上机信息查询,来增加一下理解。


1,首先正常添加windows窗体,并设置好模板窗体的界面。定义相关抽象类

重构个人版机房收费系统——模板模式_第4张图片


抽象模板:

Imports Entity
Imports chargeManageBLL
Public Class frmGroupQuery

    Protected enQueryGroup As New En_QueryGroup
    ''' <summary>
    ''' 窗体加载
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub frmGroupQuery_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        '将参数传递给实体,赋初值
        enQueryGroup.fileds1 = "1"
        enQueryGroup.fileds2 = "1"
        enQueryGroup.fileds3 = "1"

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

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

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

        combRelationA.Items.Add("与")
        combRelationA.Items.Add("或")

        combRelationB.Items.Add("与")
        combRelationB.Items.Add("或")

        '窗体加载,后两组控件默认为不可用
        combFiledB.Enabled = False
        combFiledC.Enabled = False
        combOperB.Enabled = False
        combOperC.Enabled = False

        combRelationB.Enabled = False
        txtContentB.Enabled = False
        txtContentC.Enabled = False
 
    End Sub
    ''' <summary>
    ''' 点击查询按钮,触发的事件
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub btnSelect_Click(sender As Object, e As EventArgs) Handles btnSelect.Click

        '不是组合查询
        '限制输入条件不能为空
        If combRelationA.Text = "" Then
            If combFiledA.Text = "" Or combOperA.Text = "" Or txtContentA.Text = "" Then
                MsgBox("查询条件不能为空,请填写完全!", vbOKOnly, "提示信息")
                Exit Sub
            End If
        End If

        '根据第一个组合查询条件文本内容是否为空判断下一组控件的内容是否为空
        If combRelationA.Text <> "" Then
            If combFiledA.Text = "" Or combOperA.Text = "" Or txtContentA.Text = "" Or combFiledB.Text = "" Or combOperB.Text = "" Or txtContentB.Text = "" Then
                MsgBox("查询条件不能为空,请填写完全!", vbOKOnly, "提示信息")
                Exit Sub
            End If
        End If

        '根据第二个组合查询条件文本内容是否为空判断下一组控件的内容是否为空
        If combRelationB.Text <> "" Then
            If combFiledA.Text = "" Or combOperA.Text = "" Or txtContentA.Text = "" Or combFiledB.Text = "" Or combOperB.Text = "" Or txtContentB.Text = "" Or combFiledC.Text = "" Or combOperC.Text = "" Then
                MsgBox("查询条件不能为空,请填写完全!", vbOKOnly, "提示信息")
                Exit Sub
            End If          
        End If

        Dim dt As New DataTable
        Dim queryOperator As New F_GroupQuery          '实例化外观
  
        '将参数传递给实体封装
        enQueryGroup.fileds1 = GetEnglish(combFiledA.Text)
        enQueryGroup.fileds2 = GetEnglish(combFiledB.Text)
        enQueryGroup.fileds3 = GetEnglish(combFiledB.Text)
        enQueryGroup.operator1 = combOperA.Text
        enQueryGroup.operator2 = combOperB.Text
        enQueryGroup.operator3 = combOperC.Text
        enQueryGroup.content1 = txtContentA.Text.Trim
        enQueryGroup.content2 = txtContentB.Text.Trim
        enQueryGroup.content3 = txtContentC.Text.Trim
        enQueryGroup.relation1 = combRelationA.Text.Trim
        enQueryGroup.relation2 = combRelationB.Text.Trim

        Dim strsql As String
        strsql = SelectData()

    End Sub


    ''' <summary>
    ''' 模板方法:定义虚函数GetEnglish,查询字段转化为数据库字段
    ''' </summary>
    ''' <param name="combField"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overridable Function GetEnglish(combField As String) As String
        Return ""
    End Function
    ''' <summary>
    ''' 定义虚函数GetTable,获取不同数据库的表名
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overridable Function GetTable() As String
        Return ""
    End Function
    ''' <summary>
    ''' 执行查询的关键函数
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Protected Overridable Function SelectData()
        Return ""
    End Function
    ''' <summary>
    ''' 拼接字符串
    ''' </summary>
    ''' <param name="frm"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Query(frm As frmGroupQuery) As String
        Dim sql As String = "" & frm.GetEnglish(frm.combFiledA.Text) & frm.combOperA.Text & "'" & frm.txtContentA.Text & "'"
        '非组合查询
        If frm.combRelationA.Text = "" Then
            sql = sql
        Else
            '第一个条件不为空,第二个条件为空
            If frm.combRelationB.Text = "" Then
                sql = sql & frm.GetEnglish(frm.combRelationA.Text) & " " & frm.GetEnglish(frm.combFiledB.Text) & frm.combOperB.Text & "'" & frm.txtContentB.Text & "'"
            Else
                '两个条件均不为空
                sql = sql & frm.GetEnglish(frm.combRelationA.Text) & " " & frm.GetEnglish(frm.combFiledB.Text) & frm.combOperB.Text & "'" & frm.txtContentB.Text & "'" & "" & frm.GetEnglish(frm.combRelationB.Text) & " " & frm.GetEnglish(frm.combFiledC.Text) & frm.combOperB.Text & "'" & frm.txtContentC.Text & "'"
            End If
        End If
        Return sql
    End Function

    ''' <summary>
    ''' 第一个组合关系不为空
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub combRelationA_SelectedIndexChanged(sender As Object, e As EventArgs) Handles combRelationA.SelectedIndexChanged

        combFiledB.Enabled = True
        combOperB.Enabled = True
        txtContentB.Enabled = True
        combRelationB.Enabled = True

        combFiledC.Enabled = False
        combOperC.Enabled = False
        txtContentC.Enabled = False
    End Sub
    ''' <summary>
    ''' 第二个组合关系不为空
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub combRelationB_SelectedIndexChanged(sender As Object, e As EventArgs) Handles combRelationB.SelectedIndexChanged

        combFiledC.Enabled = True
        combOperC.Enabled = True
        txtContentC.Enabled = True

    End Sub
End Class

      设置完模板窗体后,接下来就是“刻”子窗体了。添加新项——继承的窗体,设置窗体名称,点击“添加”,在弹出的继承器窗口中选择要刚刚设置的模板窗体就Ok啦。


重构个人版机房收费系统——模板模式_第5张图片


通过模板刻制出来的窗体,需要的排版、控件等等都与模板窗体完全一致,不错吧~~~


重构个人版机房收费系统——模板模式_第6张图片


子类,实现父类所定义的一个或多个抽象方法。

<span style="font-size:14px;">Imports Entity
Imports chargeManageBLL
Public Class frmOnLine

    Private Sub frmOnLine_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        combFiledA.Items.Add("卡号")
        combFiledA.Items.Add("姓名")
        combFiledA.Items.Add("上机日期")
        combFiledA.Items.Add("上机时间")
        combFiledA.Items.Add("下机日期")
        combFiledA.Items.Add("下机时间")
        combFiledA.Items.Add("消费金额")
        combFiledA.Items.Add("余额")

        combFiledB.Items.Add("卡号")
        combFiledB.Items.Add("姓名")
        combFiledB.Items.Add("上机日期")
        combFiledB.Items.Add("上机时间")
        combFiledB.Items.Add("下机日期")
        combFiledB.Items.Add("下机时间")
        combFiledB.Items.Add("消费金额")
        combFiledB.Items.Add("余额")

        combFiledC.Items.Add("卡号")
        combFiledC.Items.Add("姓名")
        combFiledC.Items.Add("上机日期")
        combFiledC.Items.Add("上机时间")
        combFiledC.Items.Add("下机日期")
        combFiledC.Items.Add("下机时间")
        combFiledC.Items.Add("消费金额")
        combFiledC.Items.Add("余额")
    End Sub

    Public Overrides Function GetEnglish(combField As String) As String
        Select Case combField
            Case "卡号"
                GetEnglish = "cardID"
            Case "姓名"
                GetEnglish = "studentName"
            Case "上机日期"
                GetEnglish = "onDate"
            Case "上机时间"
                GetEnglish = "onTime"
            Case "下机日期"
                GetEnglish = "offDate"
            Case "下机时间"
                GetEnglish = "offTime"
            Case "消费金额"
                GetEnglish = "consumeMoney"
            Case "余额"
                GetEnglish = "cash"
            Case "与"
                GetEnglish = "and"
            Case "或"
                GetEnglish = "or"
            Case Else
                GetEnglish = ""
        End Select
    End Function
    Public Overrides Function GetTable() As String
        Return "OnLine_table"
    End Function

    Protected Overrides Function SelectData() As Object
        Dim dt As New DataTable
        Dim facaonlineinfo As New F_GroupQuery
        Dim frmgroupquery As New frmGroupQuery
        Dim sql As String
        Try
            sql = frmgroupquery.Query(Me)
            dt = facaonlineinfo.QueryOnLineInfo(sql)
            If dt.Rows.Count = 0 Then
                dt.Clear()
                DataGridView1.DataSource = Nothing
                DataGridView1.Refresh()
            Else
                DataGridView1.DataSource = dt
                DataGridView1.Columns(0).Visible = False
                DataGridView1.Columns(0).HeaderText = "卡号"
                DataGridView1.Columns(1).HeaderText = "姓名"
                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, vbOKOnly, "提示信息")
        End Try
    End Function
End Class</span>

        跟以往的类抽象不同的是,模板方法是一种反向的控制结构,这种结构有时被称为“好莱坞法则”,即“别找我们,我们找你”。这指的是一个父类调用一个子类的操作,而不是相反,在程序执行时进行跟踪即可验证。


       导出到Excel表格跟VB6.0有些不同,每个窗体都一样,所以该功能提炼到模板窗体中实现即可。

首先,设置datagridview控件的[AllowUserToAddRows]属性为False,否则会出现错误:未将对象引用到实例。

<span style="font-size:14px;">''' <summary>
    ''' 导出到Excel
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub btnExportExcel_Click(sender As Object, e As EventArgs) Handles btnExportExcel.Click
        Dim MyExcel As New Excel.Application '添加工作簿
        MyExcel.Application.Workbooks.Add()   '添加表
        MyExcel.Visible = True   '打开表

        '获取datagridview的标题行赋给Excel
        'Excel标题行第一列标识为1,datagridview则为0,所以cols-1
        Dim Cols As Integer
        For Cols = 1 To DataGridView1.Columns.Count
            MyExcel.Cells(1, Cols) = DataGridView1.Columns(Cols - 1).HeaderText
        Next

        '往Excel表中添加数据
        Dim i As Integer
        For i = 0 To DataGridView1.RowCount - 1
            Dim j As Integer
            For j = 0 To DataGridView1.ColumnCount - 1
                If Me.DataGridView1(j, i).Value Is System.DBNull.Value Then
                    MyExcel.Cells(i + 2, j + 1) = ""
                Else
                    MyExcel.Cells(i + 2, j + 1) = DataGridView1(j, i).Value.ToString()

                End If
            Next
        Next</span>

        通过重构个人版机房收费,对部分设计模式有了更多的实际应用的机会,经过实战练习,在原来学习的基础上有了更深的理解。更多的知识还需要不断地去学习和积累。


你可能感兴趣的:(重构个人版机房收费系统——模板模式)