机房重构——组合查询(模板应用)

时间:2022-02-10 06:18:44

    在机房收费系统中有三个地方用到了组合查询,分别是查看学生信息,产看上机信息,查看工作记录。这三个窗体中有大量重复的代码,只有少量的代码是不同的,鉴于此种情况,这次是重构了,就不要再向第一次那样复制粘贴了,这里我们可以用到一个设计模式——模板方法模式。


    怎么用?

    我们把三个窗体共性的东西抽象出一个窗体作为模板窗体,让其他三个窗体继承这个模板窗体,再分别加上自己个性化的东西就可以了。


    注意事项

     一、模板是抽象出来的公共的窗体或者类,作为父类只是让其他子类来继承它,并不能作为三个组合查询窗体之一。因为在父类模板上的改动会延伸到子类。

     二、在设计模板的过程中,我们要注意public、protected、 private的区别。

                 public任何人都可以使用。

                 protected只有父亲和父亲的传人可以用(父类以及继承父类的子类)

                 private仅有父亲自己可以用(只有父类可以调用)

    三、注意Overridable关键字,模板中方法都要就加Overridable关键字,意思是可重写的,然后到子类中去重写这个方法。


    具体实例:

           父类窗体代码:

          

<span style="font-size:18px;"><strong>    Public comboquery As New Entity.ComboQueryEntity '实例化组合查询实体

    Public Overridable Sub frmGroupQueryPrent_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        MaximizeBox = False '不显示最大化按钮
        '将参数传给实体,赋初值
        '不同窗体字段不同,赋值为"",子窗体重写
        comboquery.Field1 = ""
        comboquery.Field2 = ""
        comboquery.Field3 = ""

        '操作符
        ComboOper1.Items.Add(">")
        ComboOper1.Items.Add("<")
        ComboOper1.Items.Add("=")
        ComboOper1.Items.Add("<>")

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

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

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

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

        '窗体加载后,后两组控件默认不可用
        ComboField2.Enabled = False
        ComboOper2.Enabled = False
        txtContent2.Enabled = False

        ComboGroup2.Enabled = False

        ComboField3.Enabled = False
        ComboOper3.Enabled = False
        txtContent3.Enabled = False

        '设置选中单元格即选中行
        DGV1.SelectionMode = DataGridViewSelectionMode.FullRowSelect

        Dim i As Integer

        '调整列宽
        For i = 0 To DGV1.Columns.Count - 1
            DGV1.Columns(i).Width = DataGridViewAutoSizeColumnsMode.AllCells
        Next

    End Sub</strong></span>

           父类查询代码:

          

<span style="font-size:18px;"><strong>   Public Overridable Sub cmdQuery_Click(sender As Object, e As EventArgs) Handles cmdQuery.Click

        '判断组合框不为空
        If ComboGroup1.Text = "" Then
            If ComboField1.Text = "" Or ComboOper1.Text = "" Or txtContent1.Text = "" Then
                MsgBox("第一行查询条件不能为空", CType(vbOKOnly + MsgBoxStyle.Exclamation, MsgBoxStyle), "提示")
                Exit Sub
            End If
        End If

        If ComboGroup1.Text <> "" Then
            If ComboField2.Text = "" Or ComboOper2.Text = "" Or txtContent2.Text = "" Then
                MsgBox("第二行查询条件不能为空", CType(vbOKOnly + MsgBoxStyle.Exclamation, MsgBoxStyle), "提示")
                Exit Sub
            End If
        Else
            If ComboGroup2.Text <> "" Then
                If ComboField3.Text = "" Or ComboOper3.Text = "" Or txtContent3.Text = "" Then
                    MsgBox("第三行查询条件不能为空", CType(vbOKOnly + MsgBoxStyle.Exclamation, MsgBoxStyle), "提示")
                    Exit Sub
                End If
            End If
        End If

        '将参数传给实体
        comboquery.dbName = GetdbName()
        comboquery.Field1 = ToEnglish(ComboField1.Text)
        comboquery.Field2 = ToEnglish(ComboField2.Text)
        comboquery.Field3 = ToEnglish(ComboField3.Text)

        comboquery.Operator1 = ComboOper1.Text.Trim
        comboquery.Operator2 = ComboOper2.Text.Trim
        comboquery.Operator3 = ComboOper3.Text.Trim

        comboquery.Content1 = txtContent1.Text.Trim
        comboquery.Content2 = txtContent2.Text.Trim
        comboquery.Content3 = txtContent3.Text.Trim

        comboquery.Relation1 = ToEnglish(ComboGroup1.Text)
        comboquery.Relation2 = ToEnglish(ComboGroup2.Text)

        '调用外观层方法
        Dim cboll As New Facade.ComboQueryFac
        Dim table As New DataTable

        '没有返回结果
        If cboll.ComboQuery(comboquery) Is Nothing Then
            MsgBox("没有记录", vbOKOnly, vbExclamation)
            DGV1.DataSource = Nothing
        Else
            '将结果返回给datatable
            table = cboll.ComboQuery(comboquery)
            DGV1.DataSource = table
        End If

    End Sub</strong></span>

         需自己定义的方法:

        

<span style="font-size:18px;"><strong> '定义虚函数ToEnglis,将查询字段转化为数据库字段
    Public Overridable Function ToEnglish(cboName As String) As String
        Return ""
    End Function

    '获得数据库表名
    Public Overridable Function GetdbName() As String
        Return ""
    End Function</strong></span>

       这里要说的是,写完模板窗体的U层之后,接着往下写就行了一直写到D层,跟其他窗体没有什么区别。只是D层我用了存储过程写的查询语句。


       子类实现:

              以查看上机信息为例:

            

<span style="font-size:18px;"><strong>Private Sub frmLineRecord_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        ComboField1.Items.Add("卡号")
        ComboField1.Items.Add("消费时间")
        ComboField1.Items.Add("消费金额")
        ComboField1.Items.Add("上机日期")
        ComboField1.Items.Add("上机时间")
        ComboField1.Items.Add("下机日期")
        ComboField1.Items.Add("下机时间")

        ComboField2.Items.Add("卡号")
        ComboField2.Items.Add("消费时间")
        ComboField2.Items.Add("消费金额")
        ComboField2.Items.Add("上机日期")
        ComboField2.Items.Add("上机时间")
        ComboField2.Items.Add("下机日期")
        ComboField2.Items.Add("下机时间")

        ComboField3.Items.Add("卡号")
        ComboField3.Items.Add("消费时间")
        ComboField3.Items.Add("消费金额")
        ComboField3.Items.Add("上机日期")
        ComboField3.Items.Add("上机时间")
        ComboField3.Items.Add("下机日期")
        ComboField3.Items.Add("下机时间")

    End Sub

    Public Overrides Function ToEnglish(cbofield As String) As String

        Select Case cbofield
            Case "卡号"
                ToEnglish = "CardID"
            Case "消费时间"
                ToEnglish = "Consumetime"
            Case "消费金额"
                ToEnglish = "Consume"
            Case "上机日期"
                ToEnglish = "Ondate"
            Case "上机时间"
                ToEnglish = "Ontime"
            Case "下机日期"
                ToEnglish = "Offdate"
            Case "下机时间"
                ToEnglish = "Offtime"
            Case "与"
                ToEnglish = "and"
            Case "或"
                ToEnglish = "or"
            Case Else
                ToEnglish = ""

        End Select

    End Function

    Public Overrides Function GetdbName() As String
        Return "T_Line"
    End Function</strong></span>

    组合查询说到这里就差不多了,关于子窗体如何继承父窗体的问题,大家可以去看这篇博客,讲的非常详细窗体继承

    分析一下我觉得我做的很不好的地方,我这里没有用到泛型,因为这里涉及到的实体比较多,当时考虑到可能会报错比较多,就没有用泛型,如果使用泛型的话,在U层和D层都要多加一些判断,去判断不同的子窗体要分别取对应哪个泛型集合,也不是太难。


   重构的过程,确确实实是一个收获的过程,继续加油!