机房重构——模板方法模式+单例模式+存储过程优化组合查询

组合查询这个功能的实现,在VB中大家已经体验过了,其中有大量的重复代码,极大地影响了系统的性能,这篇博客将为大家介绍一种面向对象的VB.NET版组合查询,其中结合模板方法模式对组合查询进行了优化,什么是模板方法模式?它的杀手锏是什么?为什么通过它我们就可以实现代码复用,我们到底可以怎么达到我们想要的结果呢?预知答案,精彩内容如下:

有关模板方法模式见博客:http://blog.csdn.net/hongwei15732623364/article/details/50659283

组合查询的实现过程:

一、准备工作:

(1)建立父窗体:

机房重构——模板方法模式+单例模式+存储过程优化组合查询_第1张图片

 

(2)建立继承窗体:

机房重构——模板方法模式+单例模式+存储过程优化组合查询_第2张图片

 

二、存储过程编写:

ALTER PROCEDURE [dbo].[PROC_Studentservice] 
	@Comboa1 varchar(50),
	@Comboa2 varchar(50),
	@Comboa3 varchar(50),
	@Combob1 varchar(50),	
	@Combob2 varchar(50),
	@Combob3 varchar(50),
	@Combod1 varchar(50),
	@Combod2 varchar(50),
	@txtc1 varchar(50),	
	@txtc2 varchar(50),	
	@txtc3 varchar(50),
	@listName varchar(20)
	
AS
	declare @strSQL varchar(500)
BEGIN
	set @strSQL='select * from '+@listName+' where '+@Comboa1+@Combob1+char(39)+@txtc1+char(39)
	if(@Combod1<>'')
	begin
	set @strSQL =@strSQL+@Combod1+CHAR(32)+@Comboa2+@Combob2+CHAR(39)+@txtc2+CHAR(39)
		if (@Combod2<>'')
		begin
		set @strSQL=@strSQL +@Combod2+CHAR(32)+@Comboa3+@Combob3+CHAR(39)+@txtc3+CHAR(39)
		end		
	end
	execute(@strSQL)
END

存储过程这段纠结了好半天,SQL语句少写一个空格,最后结果都会显示“无法找到表0”,char(),括号中的数值表示和ASC码对应,这个也是刚知道的。通过这次存储过程的使用,对它了解更深了,但有时候还是会弄错,不过没关系,尝试着去做了,总会明白过来的。

三、实现代码部分:

父窗体代码:

(1)首先窗体加载后Combobox控件中需要自动加载出应有的查询字段:

    Private Sub UGroupQuery_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        '将参数传递给实体,赋初值
        '不同窗体字段不同,赋“”,子窗体重写它
        e_group.comboa1 = ""
        e_group.comboa2 = ""
        e_group.comboa3 = ""
        '操作符
        Combob1.Items.Add(">")
        Combob1.Items.Add("<")
        Combob1.Items.Add("=")
        Combob1.Items.Add("<>")
        Combob2.Items.Add(">")
        Combob2.Items.Add("<")
        Combob2.Items.Add("=")
        Combob2.Items.Add("<>")
        Combob3.Items.Add(">")
        Combob3.Items.Add("<")
        Combob3.Items.Add("=")
        Combob3.Items.Add("<>")
        '组合关系
        Combod1.Items.Add("与")
        Combod1.Items.Add("或")
        Combod2.Items.Add("与")
        Combod2.Items.Add("或")

        '窗体加载后,后两组控件默认不可用
        Comboa2.Enabled = False
        Comboa3.Enabled = False
        Combob2.Enabled = False
        Combob3.Enabled = False
        Combod2.Enabled = False
        txtc2.Enabled = False
        txtc3.Enabled = False

        '设置选中单元格就选中行
        dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect
        Dim i As Integer
        For i = 0 To dgv.Columns.Count - 1
            dgv.Columns(i).Width = DataGridViewAutoSizeColumnMode.AllCells
        Next
    End Sub

(2)窗体的Click事件:

    Protected e_group As New Entity.GroupEntity
   
    ''' 
    ''' 查询,Click事件
    ''' 
    ''' 
    ''' 
    ''' 
    ''' 
    Private Sub btnCheck_Click(sender As Object, e As EventArgs) Handles btnCheck.Click
        dgv.DataSource = Nothing        '单击查询按钮,清空控件
        '限制第一行输入不为空
        If Combod1.Text = "" Then
            If Comboa1.Text = "" Or Combob1.Text = "" Or txtc1.Text = "" Then
                MsgBox("请输入第一行全部内容")
            End If
        End If
        '若第一个组合关系不为空,则判断前两行文本框是否为空
        If Combod1.Text <> "" Then
            If Comboa2.Text = "" Or Combob2.Text = "" Or txtc2.Text = "" Then
                MsgBox("请输入第二行全部内容")
            End If
        End If
        '若第二个组合关系不为空,则判断所有文本框是否为空
        If Combod2.Text <> "" Then
            If Comboa3.Text = "" Or Combob3.Text = "" Or txtc3.Text = "" Then
                MsgBox("请输入第三行内容")
            End If
        End If

        '将参数传给实体
        e_group.Listname = GetdbName()
        e_group.comboa1 = ToEnglish(Comboa1.Text)
        e_group.comboa2 = ToEnglish(Comboa2.Text)
        e_group.comboa3 = ToEnglish(Comboa3.Text)

        e_group.combob1 = Combob1.Text.Trim
        e_group.combob2 = Combob2.Text.Trim
        e_group.combob3 = Combob3.Text.Trim

        e_group.txtc1 = txtc1.Text.Trim
        e_group.txtc2 = txtc2.Text.Trim
        e_group.txtc3 = txtc3.Text.Trim
        '前者还是后者
        e_group.combod1 = ToEnglish(Combod1.Text)
        e_group.combod2 = ToEnglish(Combod2.Text)

        Dim dt As New DataTable
        Dim ugroup As New Facade.GroupFacade '实例化外观层
        dt = ugroup.Grouplist1(e_group)
        If dt Is Nothing Then
            MsgBox("该条件下没有记录")
        Else
            Call Todgv()
        End If
    End Sub

(3)写出模板方法模式的虚方法:

    ''' 
    ''' 模版方法,定义虚函数ToEnglish,查询字段转化为数据库字段
    ''' 
    ''' 
    ''' 
    ''' 
    Public Overridable Function ToEnglish(turnName As String) As String
        Return ""
    End Function
    ''' 
    ''' 获得数据库表名
    ''' 
    ''' 
    ''' 
    Public Overridable Function GetdbName() As String
        Return ""
    End Function
    ''' 
    ''' 将表显示到Datagridview中
    ''' 
    ''' 
    Protected Overridable Sub Todgv()

    End Sub

(4)优化控件的可用性:

''' 
    ''' 第一个组合关系不为空,则使控件可输入
    ''' 
    ''' 
    ''' 
    ''' 
    Private Sub Combod1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles Combod1.SelectedIndexChanged
        If Combod1.Text = "" Then
            Comboa2.Enabled = False
            Comboa3.Enabled = False
            Combob2.Enabled = False
            Combob3.Enabled = False
            Combod2.Enabled = False
            txtc2.Enabled = False
            txtc3.Enabled = False
        Else
            Comboa2.Enabled = True
            Combob2.Enabled = True
            Combod2.Enabled = True
            txtc2.Enabled = True
        End If
    End Sub
    ''' 
    ''' 第二个组合关系不为空,则使控件可输入
    ''' 
    ''' 
    ''' 
    ''' 
    Private Sub Combod2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles Combod2.SelectedIndexChanged
        If Combod2.Text = "" Then
            Comboa3.Enabled = False
            Combob3.Enabled = False
            txtc3.Enabled = False
        Else
            Comboa3.Enabled = True
            Combob3.Enabled = True
            txtc3.Enabled = True
        End If
    End Sub
End Class

子窗体(UStudentservice):

(1)添加单例模式:

    Private Shared Student As UStudentservice '声明一个静态变量,类似C#中static
    Private Sub New()   '初始化为私有,外部代码不能直接New该窗体
        ' 此调用是设计器所必需的。
        InitializeComponent()

        ' 在 InitializeComponent() 调用之后添加任何初始化。
    End Sub
    '写一个公有的方法检验这个类是否初始化以及被释放过
    Public Shared Function GetInstance() As UStudentservice
        If Student Is Nothing OrElse Student.IsDisposed Then '当窗体被关闭时实例化该窗体,因为关闭后不会将变量设置为nothing,只是将窗体dispose掉
            Student = New UStudentservice
            Student.MdiParent = frmMain.ActiveForm
        End If
        Return Student          '如果已经实例化,则返回窗体本身
    End Function

注意,在主窗体frmMain中的实现:

    ''' 
    ''' 学生基本信息维护窗体显示
    ''' 
    ''' 
    ''' 
    ''' 
    Private Sub 学生基本信息维护ToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles 学生基本信息维护ToolStripMenuItem.Click
        UStudentservice.GetInstance.Show()
    End Sub

(2)利用哈希表完美实现加载控件的Item,省去一个一个写进去的烦恼:

    ''' 
    ''' 加载Combo的item
    ''' 
    ''' 
    ''' 
    ''' 
    Private Sub UStudentservice_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim turnField As New Hashtable  '定义处理字符串转换的hashtable
        Dim FieldName() As String
        Dim FieldValue() As String      '使用哈希表将数据库字段进行转换
        '数据库中对应字段
        FieldName = {"卡号", "姓名", "学号", "性别", "系别", "年级", "班级", "开户人"}
        FieldValue = {"Cardno", "Studentname", "Studentno", "Sex", "Department", "Grade", "Onclass", "Holder"}

        '放到Field字段中
        Comboa1.Items.AddRange(FieldName)
        Comboa2.Items.AddRange(FieldName)
        Comboa3.Items.AddRange(FieldName)
        Comboa1.Items.Add("卡号")
        'value添加到hashtable
        For i As Integer = 0 To FieldName.Count - 1
            turnField.Add(FieldName(i), FieldValue(i))
        Next

    End Sub


(3)转换成数据库可识别的名称:

    ''' 
    ''' 加载的汉字转换陈数据库的字段
    ''' 
    ''' 
    ''' 
    ''' 
    Public Overrides Function ToEnglish(turnName As String) As String
        'Return MyBase.ToEnglish(comboa)
        Select Case turnName
            Case "卡号"
                Return "Cardno"
            Case "姓名"
                Return "Studentname"
            Case "学号"
                Return "Studentno"
            Case "性别"
                Return "Sex"
            Case "系别"
                Return "Department"
            Case "年级"
                Return "Grade"
            Case "班级"
                Return "Onclass"
            Case "开户人"
                Return "Holder"
            Case "与"
                Return "and"
            Case "或"
                Return "or"
            Case Else
                Return ""
        End Select
    End Function


(4)重写具体的方法:

    ''' 
    ''' 重写父类中方法,传数据库表名
    ''' 
    ''' 
    ''' 
    Public Overrides Function GetdbName() As String
        Return "T_Student"
    End Function
    Protected Overrides Sub Todgv()
        dgv.DataSource = Nothing

        Dim UGroupQuery As New UGroupQuery '实例化一个窗体
        Dim ugroup As New Facade.GroupFacade
        Dim table As DataTable

        Try
            table = ugroup.Grouplist1(e_group)
            If table.Rows.Count = 0 Then
                table.Clear()
                dgv.DataSource = Nothing
                dgv.Refresh()
                MsgBox("没有查询到内容")
            Else
                'dgv.DataSource = Nothing
                dgv.DataSource = table
                dgv.Columns(0).HeaderText = "卡号"
                dgv.Columns(1).HeaderText = "姓名"
                dgv.Columns(2).HeaderText = "学号"
                dgv.Columns(3).HeaderText = "性别"
                dgv.Columns(4).HeaderText = "系别"
                dgv.Columns(5).HeaderText = "年级"
                dgv.Columns(6).HeaderText = "班级"
                dgv.Columns(7).HeaderText = "开户人"

                '删除组后空白行
                dgv.AllowUserToAddRows = False

            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message.ToString, "提示")
        End Try
        
    End Sub

四、总结感受:

组合查询整体的思路和VB版的机房收费系统几乎一样,不一样的是这次我加入了设计模式,完美实现了代码复用,这两次做机房收费系统,感触最深的就是思路已经可以很容易找到,具体的模式使用还需要多锻炼,这次组合查询优化的亮点在于:

1.使用单例模式轻松搞定多窗体显示的问题,给用户带来极大方便;

2.使用模板方法模式将相同部分封装,完美实现代码复用,增加系统的性能,实现面向对象;

3.存储过程提高系统性能,使系统对数据库的访问变得简单;

4.哈希表实现控件的Item的添加,减少代码量,减少输入错误,提高工作效率。

组合查询看似复杂,但是只要找到总线,慢慢缕清思路,它便不是问题,所以写代码前最重要的过程是思考。

 

感谢您宝贵的时间,欢迎路过的大牛指正!

 


 




 

 

 

 

你可能感兴趣的:(【设计模式】)