众所周知,在面向对象的软件开发中,通过对类的封装和抽象,能够对类进行继承,从而实现代码复用和添加软件的可维护性。那么,窗口能不能继承呢?在重构机房收费系统的时候遇到了例如以下问题:
相似的几个功能,窗口布局一模一样,假设使用曾经的方法,仅仅能复制、粘贴这些窗口和控件,但是,控件能够复制,名字却不能复制;假设改当中的一项数据的话,须要改动好几个窗口,可维护性差;U层、B层、D层代码相似度非常高,代码复用性太低等等。怎么解决这些问题呢?
类能够进行抽象、封装,然后能够继承以复用,窗口能不能看做一个特殊的类?窗口和控件的属性是这个窗口类的属性,窗口和控件的事件就是这个窗口类的部分方法。完毕了窗口类的抽象,就能够对这个窗口进行继承了。
详细实现过程:
1 依照正常步骤创建父窗口;创建原则是把须要复用的控件布置好;须要复用的代码也写到父类中;不须要复用的代码即子窗口不同样的数据须要在父窗口中写成虚函数。
父窗口例如以下:
2实现窗口复用功能代码:(以收取金额和退换金额为例)
首先是实体层代码,实体层代码包含全部父窗口和子窗口须要使用到的变量(不一定跟数据库同样)。这里就不再啰嗦。
U层代码:实现接收用户输入数据和输出数据功能。
Public Class frmMDICheckCash '退出 Private Sub btnQuit_Click(sender As Object, e As EventArgs) Handles btnQuit.Click Me.Close() End Sub '导出为Excel,这里将导出EXCEL功能做成了一个模块,直接调用就可以 Private Sub btnExport_Click(sender As Object, e As EventArgs) Handles btnExport.Click Call ExportExcel.ExportExcel(DataGridView1) End Sub '查询数据方法 Private Sub btnOK_Click(sender As Object, e As EventArgs) Handles btnOK.Click '实例化一个实体类 Dim enmdicheckcash As New Charge.Entity.MDICheckCash enmdicheckcash.StartTime = CStr(DateTimePicker1.Text.Trim) '获得两个日期字符串 enmdicheckcash.OverTime = CStr(DateTimePicker2.Text.Trim) '将表名作为一个虚函数 enmdicheckcash.SearchTable = GetTable() '实例化B层类 Dim mdicheckcash As New Charge.BLL.MDICheckCash Dim myList As List(Of Charge.Entity.MDICheckCash) myList = mdicheckcash.CheckCash(enmdicheckcash) '通过B层返回值推断是否查询成功 If myList.Count = 0 Then MsgBox("信息查询错误,请又一次选择!") Else DataGridView1.DataSource = myList End If End Sub '将数据库的表名作为一个虚函数,由于子窗口须要查询的数据表不同 Protected Overridable Function GetTable() As String Return "" '子窗口须要继承并实现这种方法 End Function End Class代码分析:两个子窗口功能不同,须要使用的数据表也不一样,所以要把表名作为一个变量,变量须要在U层赋值,所以须要做成实体。U层把获得表名作为一个虚方法,执行的时候进行赋值,然后将表名放到实体中,在D层使用。
由于B层、接口层和工厂层代码没有特殊之处,这里不再展示。
接下来是D层代码:
Imports System.Data.SqlClient Imports System.Configuration Imports Charge.DAL.sqlHelper Public Class SQLServerMDICheckCash : Implements Charge.IDAL.IMDICheckCash Public Function SelectInfo(enmdicheckcash As Charge.Entity.MDICheckCash) As List(Of Charge.Entity.MDICheckCash) Implements IDAL.IMDICheckCash.SelectInfo Dim help As New Charge.DAL.sqlHelper Dim strSQL As String Dim median As DataTable '存储过程调用 strSQL = "PROC_MDICheckCash" Dim sqlPara As SqlParameter() = { New SqlParameter("@TableName", enmdicheckcash.SearchTable), New SqlParameter("@StartTime", enmdicheckcash.StartTime), New SqlParameter("@OverTime", enmdicheckcash.OverTime) } median = help.ParaSelect(strSQL, CommandType.StoredProcedure, sqlPara) '将表格转换为实体集合返回B层 Dim myList As List(Of Charge.Entity.MDICheckCash) Dim mhelp As New Charge.Entity.ModeHelper myList = mhelp.convertToList(Of Charge.Entity.MDICheckCash)(median) Return myList End Function End Class代码分析:D层带式实现了数据库查询功能,这里调用了sqlhelper和实体转换模块,而且使用存储过程来实现数据查询功能。存储过程使用了三个參数,表名和两个日期,最后返回一个实体集合。
创建子窗口:在创建子窗口的时候须要选择“继承的窗口”,然后选择继承的父窗口就可以。子窗口代码:
Public Class frmCollectCash Dim enmdicheckcash As New Charge.Entity.MDICheckCash Protected Overrides Function GetTable() As String ' 给实体赋值 enmdicheckcash.SearchTable = "dbo.Recharge_Info" Return enmdicheckcash.SearchTable End Function End Class代码分析:子窗口仅仅须要实现父窗口中的虚方法就可以,这里仅仅有一个虚方法(获得表名),直接复制就可以实现。
存储过程代码不予展示。
总结:窗口的继承大大降低了工作量,添加了系统的可维护性,降低了代码的冗余,可是也使系统的结构更加复杂。
思想:遇到问题不可怕,仅仅要分析得当,总会找到解决方法的。