在开始本篇博文之前,我们先来看一下下面截取的几幅图片:
1、组合查询
2、根据卡号查询记录并导出到Excel表格
3、按照指定的时间范围查询记录
是的,放眼望去,如果除去要实现的功能只考虑这三组图片的外观,那么每组的两张图片简直就是一个用模子刻出来的嘛~~~~~这就涉及到博文的主题了——模板模式。
模板模式,提供了一个代码复用平台,当不变和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现,形成了代码冗余,而且不易于维护,而模板模式就是把这些不变行为搬移到单一的地方(即超类),然后通过多态实现代码的复用。
有了模板模式,最直观的一点好处就是再也不用花费很多时间在设置窗体界面上了(特别是组合查询),只要做个模子,直接“刻”就行啦~~。接下来就通过一个实例:学生上机信息查询,来增加一下理解。
1,首先正常添加windows窗体,并设置好模板窗体的界面。定义相关抽象类
抽象模板:
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啦。
通过模板刻制出来的窗体,需要的排版、控件等等都与模板窗体完全一致,不错吧~~~
<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>
通过重构个人版机房收费,对部分设计模式有了更多的实际应用的机会,经过实战练习,在原来学习的基础上有了更深的理解。更多的知识还需要不断地去学习和积累。