个人机房重构——组合查询及优化

来源:互联网 发布:ps -ef|grep java 编辑:程序博客网 时间:2024/04/26 14:19


        个人机房重构逐渐接近尾声,就遇到了组合查询,本来组合查询并不是一个很难的问题。但是,整个机房重构的过程中,我们要利用组合查询完成学生基本信息维护、学生上机统计信息查询、操作员工作记录、学生上机状态查询。同时我们注意到的是,这几个功能几乎完全一样,只是所要查询到的条件略有差别,大量的重复可不是面向对象的优点,于是我们就开始想解决方案。大话设计模式的学习给我们带来了福音。

模板方法

        当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理。
         模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。
                
     
         模板方法模式是通过把不变的行为搬移到超类,去除子类中的重复代码来体现它的优势,也就是说,模板方法就是提供了一个很好的代码复用平台。那么,说的再多不实践是体会不到的,那么就让我们一起看看有什么具体的应用。


父窗体及优化

           为什么说是优化的呢?因为,在操作员工作记录中,我们会用到日期和时间查询。但是,一个小小的TextBox怎么能满足我们的要求呢?既然是时间,那么就有专门的控件:DateTimePicker
           那么,让我们看看父窗体。



代码解析

具体如何实现我们在代码中进行说明:

Public Class TemplateMethod    '实例化组合查询的实体    Protected GroupInquire As New Entity.TemplateMethodEntity    '定义接收查询条件的变量    Public txtRemark1 As String    Public txtRemark2 As String    Public txtRemark3 As String    Private Sub TemplateMethod_Load(sender As Object, e As EventArgs) Handles MyBase.Load        dtp1.Visible = False            'DateTimePicker控件的可见性        dtp2.Visible = False        dtp3.Visible = False        cmbName2.Enabled = False        '控件的可用性        cmbName3.Enabled = False        cmbOper2.Enabled = False        cmbOper3.Enabled = False        cmbGroup2.Enabled = False        txtSelect2.Enabled = False        txtSelect3.Enabled = False        '自动调整列宽        Dim i As Integer        For i = 0 To dgvLine.Columns.Count - 1            dgvLine.Columns(i).Width = DataGridViewAutoSizeColumnMode.AllCells        Next    End Sub    '查询    '点击查询按钮    Private Sub btnOK_Click(sender As Object, e As EventArgs) Handles btnOK.Click        Dim frm As New TemplateMethod        '判断查询内容是否为空        If cmbGroup1.Text = "" Then            If cmbName1.Text = "" Or cmbOper1.Text = "" Then                MsgBox("字段名或运算符不能为空!", , "提示!")                Exit Sub            End If        End If        If txtSelect1.Text = "" And dtp1.Text = "" Then            MsgBox("查询内容不能为空!", , "警告")            Exit Sub        End If        '判断第二行是否为空        If cmbGroup1.Text <> "" Then            If cmbName1.Text = "" Or cmbOper1.Text = "" Or cmbName2.Text = "" Or cmbOper2.Text = "" Then                MsgBox("字段名或运算符不能为空!", , "提示!")                Exit Sub            ElseIf txtSelect1.Text = "" And dtp1.Text = "" Then                MsgBox("第一行查询条件不能为空!")                Exit Sub            ElseIf txtSelect2.Text = "" And dtp2.Text = "" Then                MsgBox("第二行查询条件不能为空!")                Exit Sub            End If        End If        '判断第三行是否为空        If cmbGroup2.Text <> "" Then            If cmbName1.Text = "" Or cmbOper1.Text = "" Or cmbName2.Text = "" Or cmbOper2.Text = "" Or cmbName3.Text = "" Or cmbOper3.Text = "" Then                MsgBox("您输入的查询条件不能为空!", , "提示!")                Exit Sub            ElseIf txtSelect1.Text = "" And dtp1.Text = "" Then                MsgBox("第一行查询条件不能为空!", , "提示")                Exit Sub            ElseIf txtSelect2.Text = "" And dtp2.Text = "" Then                MsgBox("第二行查询条件不能为空!", , "提示")                Exit Sub            ElseIf txtSelect3.Text = "" And dtp3.Text = "" Then                MsgBox("第三行查询条件不能为空!", , "提示")                Exit Sub            End If        End If        '将参数传给实体        GroupInquire.DbName = GetdbName()        GroupInquire.cmbName1 = GetEnglish(cmbName1.Text)        GroupInquire.cmbName2 = GetEnglish(cmbName2.Text)        GroupInquire.cmbName3 = GetEnglish(cmbName3.Text)        GroupInquire.cmbOper1 = cmbOper1.Text.Trim        GroupInquire.cmbOper2 = cmbOper2.Text.Trim        GroupInquire.cmbOper3 = cmbOper3.Text.Trim        GroupInquire.txtSelect1 = txtRemark1                  '设置一个变量,将textBox或者DateTimePicker控件的值赋值后传递给实体        GroupInquire.txtSelect2 = txtRemark2        GroupInquire.txtSelect3 = txtRemark3        GroupInquire.cmbGroup1 = GetEnglish(cmbGroup1.Text)        GroupInquire.cmbGroup2 = GetEnglish(cmbGroup2.Text)        GroupInquire.SqlText = Query(frm, GroupInquire)        '将拼接的字符串传递给实体层        '进行数据查询并返回dt        Dim dt As New DataTable        Dim Generalfacade As New Facade.TemplateMethodFacade        dt = Generalfacade.SelectInfo(GroupInquire)        If (dt.Rows.Count = 0) Then                                 '若是没有数据,则清空原来查询到的数据            MsgBox("没有符合条件的记录!", , "提示!")            dt.Clear()            dgvLine.DataSource = Nothing            dgvLine.Refresh()            Exit Sub        Else            Call Todgv(dt)              ' 若是查询到数据,返回dt表,等待子类接收        End If    End Sub    '连接字符串,以便供给D层进行查询    Public Function Query(frm As TemplateMethod, ByVal GroupInquire As Entity.TemplateMethodEntity) As String        Dim sql As String        sql = GroupInquire.cmbName1 & GroupInquire.cmbOper1 & "'" & GroupInquire.txtSelect1 & "'"        If Trim(GroupInquire.cmbGroup1) <> "" Then            If Trim(GroupInquire.cmbGroup2) = "" Then   '有两组查询条件                sql = sql & GroupInquire.cmbGroup1 & GroupInquire.cmbName2 & GroupInquire.cmbOper2 & "'" & GroupInquire.txtSelect2 & "'"            Else                sql = sql & GroupInquire.cmbGroup1 & GroupInquire.cmbName2 & GroupInquire.cmbOper2 & "'" & GroupInquire.txtSelect2 & "'" & GroupInquire.cmbGroup2 & GroupInquire.cmbName3 & GroupInquire.cmbOper3 & "'" & GroupInquire.txtSelect3 & "'"            End If        End If        Return sql    End Function    ' 转换中文字符为英文字符    Public Overridable Function GetEnglish(cmbName As String) As String        Return ""    End Function    '获得所要查询数据库表    Protected Overridable Function GetdbName() As String        Return ""    End Function    ' 传递父类的datatable表给子类    Protected Overridable Sub Todgv(ByVal dt As DataTable)    End Sub    Private Sub cmbGroup1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cmbGroup1.SelectedIndexChanged        If cmbGroup1.Text = "" Then            cmbName2.Enabled = False              '如果没有选择第一个组合查询,则之后的控件都不可用            cmbName3.Enabled = False            cmbOper2.Enabled = False            cmbOper3.Enabled = False            cmbGroup2.Enabled = False            txtSelect2.Enabled = False            txtSelect3.Enabled = False        Else            cmbName2.Enabled = True            cmbOper2.Enabled = True            txtSelect2.Enabled = True            cmbGroup2.Enabled = True        End If    End Sub    Private Sub cmbGroup2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cmbGroup2.SelectedIndexChanged        If cmbGroup2.Text = "" Then                    '如果没有选择第二个组合查询,则之后的控件都不可用            cmbName3.Enabled = False            cmbOper3.Enabled = False            txtSelect3.Enabled = False        Else            cmbName3.Enabled = True            cmbOper3.Enabled = True            txtSelect3.Enabled = True        End If    End Sub</span>


以上基本上就是父窗体的代码了,重要的是理解,多条件的组合查询如何完成和实现就足够了。

优化

下面的代码就是对于应用了DateTimePicker控件的实现

<span style="font-size:18px;"> '判断查询的是否为时间。    Private Sub txtSelect1_GotFocus(sender As Object, e As EventArgs) Handles txtSelect1.GotFocus        If cmbName1.Text = "上机日期" Or cmbName1.Text = "下机日期" Or cmbName1.Text = "上机时间" Or cmbName1.Text = "下机时间" Then            dtp1.Format = DateTimePickerFormat.Custom            dtp1.Visible = True            txtSelect1.Visible = False            If cmbName1.Text = "上机日期" Or cmbName1.Text = "下机日期" Then                txtRemark1 = Format(dtp1.Value, "yyyy-MM-dd")            ElseIf cmbName1.Text = "上机时间" Or cmbName1.Text = "下机时间" Then                dtp1.Format = DateTimePickerFormat.Time                txtRemark1 = Format(dtp1.Value, "hh:mm:ss")            End If        End If    End Sub    '若是TextBox失去焦点,判断若不是采用的DateTime控件,则将TextBox中数据传入实体层    Private Sub txtSelect1_LostFocus(sender As Object, e As EventArgs) Handles txtSelect1.LostFocus        If dtp1.Visible = False Then            txtRemark1 = txtSelect1.Text.Trim()        End If    End Sub    '当cmbName重新获得焦点时,恢复初始状态    Private Sub cmbName1_GotFocus(sender As Object, e As EventArgs) Handles cmbName1.GotFocus        dtp1.Visible = False        txtSelect1.Visible = True    End Sub</span>

以上只是对于其中一个CmbName的判断,同样的方法判断三次就可以了。就可以实现两个控件的相互切换了。

子类窗体的实现

子类窗体继承父类窗体的属性来实现模板方法。具体步骤如下:

子类窗体的创建过程





 子窗体代码:

<span style="font-size:18px;">Public Class frmInquryOperator    Private Sub frmInquryOperator_Load(sender As Object, e As EventArgs) Handles MyBase.Load        cmbName1.Items.Add("教师")        cmbName1.Items.Add("上机日期")        cmbName1.Items.Add("上机时间")        cmbName1.Items.Add("下机日期")        cmbName1.Items.Add("下机时间")        cmbName1.Items.Add("机器名")        cmbName1.SelectedIndex = 0        cmbOper1.Items.Add("=")        cmbOper1.Items.Add("<>")        cmbOper1.Items.Add(">")        cmbOper1.Items.Add("<")        cmbOper1.SelectedIndex = 0        cmbName2.Items.Add("教师")        cmbName2.Items.Add("上机日期")        cmbName2.Items.Add("上机时间")        cmbName2.Items.Add("下机日期")        cmbName2.Items.Add("下机时间")        cmbName2.Items.Add("机器名")        cmbName2.SelectedIndex = 0        cmbOper2.Items.Add("=")        cmbOper2.Items.Add("<>")        cmbOper2.Items.Add(">")        cmbOper2.Items.Add("<")        cmbOper2.SelectedIndex = 0        cmbName3.Items.Add("教师")        cmbName3.Items.Add("上机日期")        cmbName3.Items.Add("上机时间")        cmbName3.Items.Add("下机日期")        cmbName3.Items.Add("下机时间")        cmbName3.Items.Add("机器名")        cmbName3.SelectedIndex = 0        cmbOper3.Items.Add("=")        cmbOper3.Items.Add("<>")        cmbOper3.Items.Add(">")        cmbOper3.Items.Add("<")        cmbOper3.SelectedIndex = 0        cmbGroup1.Items.Add("与")        cmbGroup1.Items.Add("或")        cmbGroup2.Items.Add("与")        cmbGroup2.Items.Add("或")    End Sub    '将中文字符串转换为英语    Public Overrides Function GetEnglish(cmbName As String) As String        Select Case cmbName            Case "教师"                GetEnglish = "UserID"            Case "上机日期"                GetEnglish = "LoginDate"            Case "上机时间"                GetEnglish = "LoginTime"            Case "下机日期"                GetEnglish = "LogoutDate"            Case "下机时间"                GetEnglish = "LogoutTime"            Case "机器名"                GetEnglish = "Computer"            Case "与"                GetEnglish = " and "            Case "或"                GetEnglish = " or "            Case Else                GetEnglish = ""        End Select    End Function    '传数据库表名    Protected Overrides Function GetdbName() As String        Return "WorkLog_Info"    End Function    '查询并把数据显示到DataGridView中    Protected Overrides Sub Todgv(ByVal dt As DataTable)        Try            dgvLine.DataSource = dt            dgvLine.Columns(0).HeaderText = "教师"            dgvLine.Columns(0).Frozen = True            dgvLine.Columns(1).HeaderText = "级别"            dgvLine.Columns(1).Frozen = True            dgvLine.Columns(2).HeaderText = "登陆日期"            dgvLine.Columns(2).Frozen = True            dgvLine.Columns(3).HeaderText = "登陆时间"            dgvLine.Columns(3).Frozen = True            dgvLine.Columns(4).HeaderText = "下机日期"            dgvLine.Columns(4).Frozen = True            dgvLine.Columns(5).HeaderText = "下机时间"            dgvLine.Columns(5).Frozen = True            dgvLine.Columns(6).HeaderText = "机器名"            dgvLine.Columns(6).Frozen = True        Catch ex As Exception            MsgBox(ex.Message, vbOKOnly, "提示")        End Try    End SubEnd Class</span>

D层代码

Public Function ISelect(GroupInquire As Entity.TemplateMethodEntity) As DataTable Implements ITemplateMethodDAL.ISelect        Dim dt As DataTable        Dim cmdText As String        Dim sqlhelper As New SQLHelper.SqlHelper        cmdText = "select * from " & GroupInquire.DbName & " Where " & GroupInquire.SqlText      ‘拼接查询语句,连接字符串    '模板的无参查询        dt = sqlhelper.ExecSelect(cmdText, CommandType.Text)        Return dt    End Function


总结:将拼接字符串放在U层,并传给实体层,在D层查询时进行接收,这样方便以后的修改。组合查询是对模板方法的一次很好的利用,通过不断地实践来合理的运用设计模式,会给我们的编程带来巨大的好处。简单易复用的代码永远是最好的。


0 0
原创粉丝点击