【机房重构】模板方法模式应用—组合查询

一.定义

	模板方法模式(TemplateMethod):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

二.特点
 
  
  1. 在使用继承的基础上,要考虑使用模板方法。将要成为子类的模板,所有重复的代码都应该要上升到父类去,而不是让每个子类都去重复。当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其中个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理。
  2. 提高代码的复用。通过把不变行为搬移到超类,去除子类中的重复代码来体现它的优势。
  3. 重分解以一般化。当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。首先,需要我们识别这些行为,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。这样,就帮助子类摆脱重复的不变行为的纠缠。

三.结构

【机房重构】模板方法模式应用—组合查询_第1张图片

	
	AbstractClass是抽象类,其实也就是一抽象模板,定义并实现了一个模板方法。ConcreteClass实现父类所定义的一个或多个抽象方法。每一个AbstractClass都可以有任意多个ConcreteClass与之对应,而每一个ConcreteClass都可以给出这些抽象方法的不同实现,从而使得顶级逻辑的实现各不相同。

四.代码示例

	功能介绍:根据选择不同字段,查询数据库,将结果显示在窗体中的DataGridview表格中。

	继承窗体。使用模板方法的前提是使用继承,并且继承具有意义。小编我先是画出了一个组合查询父窗体,由操作员工作记录来继承。

【机房重构】模板方法模式应用—组合查询_第2张图片

【机房重构】模板方法模式应用—组合查询_第3张图片

父类UI层代码展示:

Public Class FrmGroupQuery

    '定义组合查询的实体
    Protected eGroupQuery As New Entity.GroupQueryEntity

    '窗体加载
    Private Sub FrmGroupQuery_Load(sender As Object, e As EventArgs) Handles Me.Load
        '窗体加载时,给字段、操作符、组合关系赋值
        '加载组合关系
        ComRelation1.Items.Add("与")
        ComRelation1.Items.Add("或")

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

        '给操作符赋值
        ComOperation1.Items.Add(">")
        ComOperation1.Items.Add("<")
        ComOperation1.Items.Add("=")
        ComOperation1.Items.Add("<>")

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

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

        '窗体加载后,后两行文本框不能用
        ComFields2.Enabled = False
        ComOperation2.Enabled = False
        txtContext2.Enabled = False

        ComFields3.Enabled = False
        ComOperation3.Enabled = False
        txtContext3.Enabled = False
    End Sub

    Private Sub btnCheck_Click(sender As Object, e As EventArgs) Handles btnCheck.Click
        '先将dataGridview中清空
        grid.DataSource = Nothing

        '判断文本框、组合框是否为空
        '第一个组合关系为空时,第一行的内容均不能为空
        If ComRelation1.Text = "" Then
            If ComFields1.Text = "" Or ComOperation1.Text = "" Or txtContext1.Text = "" Then
                MsgBox("第一行查询条件不能为空,请完善", "提示")
                Exit Sub
            End If
        End If

        '第一个组合关系文本框不为空,则判断前两行不能为空
        If ComRelation1.Text <> "" Then
            If ComFields1.Text = "" Or ComOperation1.Text = "" Or txtContext1.Text = "" Or
                ComFields2.Text = "" Or ComOperation2.Text = "" Or txtContext2.Text = "" Then
                MsgBox("所输入的查询条件不能为空,请完善", "提示")
                Exit Sub
            End If
        End If

        '第二个组合关系文本框不为空,判断所有的不为空
        If ComRelation2.Text <> "" Then
            If ComFields1.Text = "" Or ComOperation1.Text = "" Or txtContext1.Text = "" Or
                ComFields2.Text = "" Or ComOperation2.Text = "" Or txtContext2.Text = "" Or
                ComFields3.Text = "" Or ComOperation3.Text = "" Or txtContext3.Text = "" Then
                MsgBox("所输入的查询条件不能为空,请完善", "提示")
            End If
        End If
        '给实体赋值(在实体层新建一个实体类)
        eGroupQuery.Fields1 = GetDBName(ComFields1.Text.Trim())
        eGroupQuery.Fields2 = GetDBName(ComFields2.Text.Trim())
        eGroupQuery.Fields3 = GetDBName(ComFields3.Text.Trim())

        eGroupQuery.Operation1 = ComOperation1.Text.Trim()
        eGroupQuery.Operation2 = ComOperation2.Text.Trim()
        eGroupQuery.Operation3 = ComOperation3.Text.Trim()

        eGroupQuery.Context1 = txtContext1.Text.Trim()
        eGroupQuery.Context2 = txtContext2.Text.Trim()
        eGroupQuery.Context3 = txtContext3.Text.Trim()

        eGroupQuery.Relation1 = GetDBName(ComRelation1.Text.Trim())
        eGroupQuery.Relation2 = GetDBName(ComRelation2.Text.Trim())
        eGroupQuery.GetList = GetList()

        Dim fa As New Facade.Facade
        Dim dt As New DataTable
        dt = fa.Query(eGroupQuery)

        If (dt.Rows.Count = 0) Then
            MsgBox("没有符合条件的记录,请重新选择查询条件!")
            Exit Sub
        Else
            Call Dview()
        End If
    End Sub

    '定义虚函数GetList,获取不同数据库的表名
    Protected Overridable Function GetList() As String
        Return ""
    End Function
    '定义虚函数GetDBName,获取不同数据库的字段名
    Protected Overridable Function GetDBName(ByVal control As String) As String
        Return ""
    End Function

    '定义虚函数Dview,将数据显示到控件中
    Protected Overridable Sub Dview()

    End Sub
    '组合关系框是否有值会影响到下边行能否操作
    Private Sub ComRelation1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComRelation1.SelectedIndexChanged
        If ComRelation1.Text <> "" Then
            ComFields2.Enabled = True
            ComOperation2.Enabled = True
            txtContext2.Enabled = True

        End If
    End Sub

    Private Sub ComRelation2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComRelation2.SelectedIndexChanged
        If ComRelation2.Text <> "" Then
            ComFields3.Enabled = True
            ComOperation3.Enabled = True
            txtContext3.Enabled = True

        End If
    End Sub
End Class


子类UI层代码展示:

Imports System.Collections  '引入哈希表
Public Class FrmCheckWorklog

    Private Sub FrmCheckWorklog_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        '表名
        Me.Text = "操作员工作记录"

        Dim haField As New Hashtable '定义处理字段名转换的hashtable

        '使用哈希表进行数据库字段进行转换
        Dim fieldName() As String
        Dim fielValue() As String

        '数据库中的字段对应相应的中文
        fieldName = {"教师", "注册时间", "注销时间", "机器名"}
        fielValue = {"UserID", "loginDateTime", "logoutDateTime", "Computer"}

        '放到field字段中
        ComFields1.Items.AddRange(fieldName)
        ComFields2.Items.AddRange(fieldName)
        ComFields3.Items.AddRange(fieldName)

        '中文为key,英文为value添加到hashtable
        For i As Integer = 0 To fieldName.Count - 1
            haField.Add(fieldName(i), fielValue(i))
        Next
    End Sub
    '重写转换成数据库字段方法
    Protected Overrides Function GetList() As String
        Return "WorkLog_Info"
    End Function

    '重写转换成数据库字段方法
    Protected Overrides Function GetDBName(control As String) As String
        Select Case (control)
            Case "教师"
                Return "UserID"
            Case "注册时间"
                Return "loginDateTime"
           
            Case "注销时间"
                Return "logoutDateTime"
            Case "机器名"
                Return "Computer"
            Case "或"
                Return "or"
            Case "与"
                Return "and"
            Case Else
                Return ""
        End Select
    End Function

    Protected Overrides Sub Dview()
        '每次数据库查询清空表
        grid.DataSource = Nothing

        '表格控件绑定数据源字段
        '调用外观,进行传递参数
        Dim fac As New Facade.Facade
        Dim dt As New DataTable

        dt = fac.Query(eGroupQuery)

        If dt.Rows.Count = 0 Then
            MsgBox("没有记录,请重新进行查询!", "提示")
            grid.DataSource = Nothing
        Else
            grid.DataSource = dt	'将所查到的结果显示在grid表格中
            grid.Columns(0).HeaderText = "教师"
            grid.Columns(1).HeaderText = "注册时间"
            grid.Columns(2).HeaderText = "注销时间"
            grid.Columns(3).HeaderText = "机器名"
            grid.Columns(4).Visible = False
            grid.DefaultCellStyle.Font = New Font("微软雅黑", 12)	'设置字体
            grid.ReadOnly = True
            grid.AutoResizeColumns()
            '删除最后一空白行
            grid.AllowUserToAddRows = False
        End If
    End Sub
End Class


	在代码实现中,父类定义的查询方法就是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。所以,在子类中,写入具体所要查询的数据库表,字段。

五.总结

	模板方法模式最大的特点就是解决了代码重复,提高编程效率。通过这一阶段的学习,小编对模板方法模式进行了深入的学习,认为设计模式真是需要我们用心去钻研,不断实践,反复学习。

你可能感兴趣的:(【机房重构】模板方法模式应用—组合查询)