• 重构ASP.NET程序继承


    原程序,可以从下面地址下载:http://download.cnblogs.com/insus/ASPDOTNET/Ref_Org.rar

    数据库SQL Server 2008 R2,数据名为[Demo],它有四张表[UnitCode1], [UnitCode2], [UnitCode3], [UnitCode4],每个表有几个字段[Unit1~4],[Description],[CreateBy],[CreateDate],[UpdateBy],[UpdateDate],此四个表的主键分别为[Unit1],[Unit2],[Unit3]和[Unit4],其余字段名称四张表都一样。数据库还有各个表的相关的存储过程。

    程序中有一个接口,是为了设置网页标题。数据库四张表对应的类别,程序应用了母版,有5个网页,Default.aspx, UnitCode1.aspx, UnitCode2.aspx, UnitCode3.aspx和UnitCode4.aspx 。每个网页分别也是对各自的表进行添加,显示,更新以及删除记录的功能。

    其实,这就是一个小程序,基本的功能都齐全。

    -------------------------------------------------------------------------------------------------------------------------------------

    根据此篇博文,我们来学习一下继承。
    打开程序,我们会到四个网页的cs代码与四个类别98%相同,只是每个表的主键名,以及存储过程名称等不一样。继承是把相同而共用的属性,方法,函数放置于父类中,这样继承的类,就是使用到这些共用的protected或public的程序块。尽可能简化,变化的地方尽量未端化去维护。

    我们创建一个父类,比如叫BaseUnitCode.cs吧。

    首先我们对比四个类别中,属性部分,只有

     private string _Unit1;      
    
    public string Unit1
     {
          get { return _Unit1; }
          set { _Unit1 = value; }
    }       


    不相同,因此我们就把它留在原本的类别中。其余的属性都移至父类BaseUnitCode,还有一句,就是逻辑处理的类实例

    BusinessBase objBusinessBase = new BusinessBase();


    在每个类别中也一样,因此也移至父类,下面是刚才重构好的父类。



    接下来,我看到每个类别的GetAll(), Insert(), Update(), Delete()方法中,只有一些参数名,参数值,以及存储过程名有差异。下面是每个方法移至父类之后,作相应的修改:

    GetAll()方法:


    Comment out的代码,就是移到父类的代码,需要修改方法以及修饰符为Protected,这因为只是想让继承这个父类的类访问到即可。而刚才上面属性,还是保持原样“public”。
    由于存储程名称在每个类别都不一样,因此方法名改为带一个参数的方法。


    Insert()方法:


    重构之后,Insert()方法被改为带三个参数的方法,这样解决传入主键,主键值,以及Insert的存储过程不一样的问题。

    同样,Update():



    Delete()方法重构:

     
    Ok,我们的父类重构好了:

    BaseUnitCode.cs
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Web;
    
    /// <summary>
    /// Summary description for BaseUnitCode
    /// </summary>
    namespace Insus.NET
    {
        public class BaseUnitCode
        {
            private string _Description;
            private string _CreateBy;
            private string _UpdateBy;
    
            public string Description
            {
                get { return _Description; }
                set { _Description = value; }
            }
            public string CreateBy
            {
                get { return _CreateBy; }
                set { _CreateBy = value; }
            }
            public string UpdateBy
            {
                get { return _UpdateBy; }
                set { _UpdateBy = value; }
            }
    
            BusinessBase objBusinessBase = new BusinessBase();
    
            public BaseUnitCode()
            {
                //
                // TODO: Add constructor logic here
                //
            }     
    
            protected DataTable GetAll(string procedureName)
            {
                return objBusinessBase.GetDataToDataSet(procedureName).Tables[0];
            }
    
            protected void Insert(string paramName, string paramValue, string procedurename)
            {
                Parameter[] parameter = {
                                           new Parameter (paramName,SqlDbType.NVarChar,-1,paramValue),
                                           new Parameter ("@Description",SqlDbType.NVarChar,-1,_Description),
                                           new Parameter ("@CreateBy",SqlDbType.NVarChar,-1,_CreateBy)
                                        
                                        };
                objBusinessBase.ExecuteProcedure(procedurename, parameter);
            }
    
            protected void Update(string paramName, string paramValue, string procedurename)
            {
                Parameter[] parameter = {
                                           new Parameter (paramName,SqlDbType.NVarChar,-1,paramValue),
                                           new Parameter ("@Description",SqlDbType.NVarChar,-1,_Description),
                                           new Parameter ("@UpdateBy",SqlDbType.NVarChar,-1,_UpdateBy)
                                        };
                objBusinessBase.ExecuteProcedure(procedurename, parameter);
            }
           
            protected void Delete(string paramName, string paramValue, string procedurename)
            {
                Parameter[] parameter = {
                                           new Parameter (paramName,SqlDbType.NVarChar,-1,paramValue)
                                        };
                objBusinessBase.ExecuteProcedure(procedurename, parameter);
            }
        }
    }


    接下来,我们需要在每一个UnitCode1.cs至UnitCode4.cs分别继承这个父类,下面只演法UnitCode1.cs,其余的UnitCode2至UnitCode4参考就是了。

     

     下面是重构好的类别:

    UnitCode1.cs
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Web;
    
    /// <summary>
    /// Summary description for UnitCode1
    /// </summary>
    namespace Insus.NET
    {
        public class UnitCode1 : BaseUnitCode
        {
            private string _Unit1;
            public string Unit1
            {
                get { return _Unit1; }
                set { _Unit1 = value; }
            }
    
            public UnitCode1()
            {
                //
                // TODO: Add constructor logic here
                //
            }
    
            public DataTable GetAll()
            {
                return GetAll("usp_UnitCode1_GetAll");
            }
            public void Insert()
            {
                Insert("@Unit1", _Unit1, "usp_UnitCode1_Insert");
            }
            public void Update()
            {
                Update("@Unit1", _Unit1, "usp_UnitCode1_Update");
            }
            public void Delete()
            {
                Delete("@Unit1", _Unit1, "usp_UnitCode1_Delete");
            }
        }
    }
    UnitCode2.cs
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Web;
    
    /// <summary>
    /// Summary description for UnitCode1
    /// </summary>
    namespace Insus.NET
    {
        public class UnitCode2 : BaseUnitCode
        {
            private string _Unit2;
            public string Unit2
            {
                get { return _Unit2; }
                set { _Unit2 = value; }
            }
            
            public UnitCode2()
            {
                //
                // TODO: Add constructor logic here
                //
            }
    
            public DataTable GetAll()
            {
                return GetAll("usp_UnitCode2_GetAll");
            }
            public void Insert()
            {
                Insert("@Unit2", _Unit2, "usp_UnitCode2_Insert");
            }
            public void Update()
            {
                Update("@Unit2", _Unit2, "usp_UnitCode2_Update");
            }
            public void Delete()
            {
                Delete("@Unit2", _Unit2, "usp_UnitCode2_Delete");
            }
        }
    }
    UnitCode3.cs
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Web;
    
    /// <summary>
    /// Summary description for UnitCode3
    /// </summary>
    namespace Insus.NET
    {
        public class UnitCode3 : BaseUnitCode
        {
            private string _Unit3;
    
            public string Unit3
            {
                get { return _Unit3; }
                set { _Unit3 = value; }
            }
           
            public UnitCode3()
            {
                //
                // TODO: Add constructor logic here
                //
            }
    
            public DataTable GetAll()
            {
                return GetAll("usp_UnitCode3_GetAll");
            }
            public void Insert()
            {
                Insert("@Unit3", _Unit3, "usp_UnitCode3_Insert");
            }
            public void Update()
            {
                Update("@Unit3", _Unit3, "usp_UnitCode3_Update");
            }
            public void Delete()
            {
                Delete("@Unit3", _Unit3, "usp_UnitCode3_Delete");
            }
        }
    }
    UnitCode4.cs
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Web;
    
    /// <summary>
    /// Summary description for UnitCode1
    /// </summary>
    namespace Insus.NET
    {
        public class UnitCode4 : BaseUnitCode
        {
            private string _Unit4;
    
            public string Unit4
            {
                get { return _Unit4; }
                set { _Unit4 = value; }
            }
           
            public UnitCode4()
            {
                //
                // TODO: Add constructor logic here
                //
            }
    
            public DataTable GetAll()
            {
                return GetAll("usp_UnitCode4_GetAll");
            }
            public void Insert()
            {
                Insert("@Unit4", _Unit4, "usp_UnitCode4_Insert");
            }
            public void Update()
            {
                Update("@Unit4", _Unit4, "usp_UnitCode4_Update");
            }
            public void Delete()
            {
                Delete("@Unit4", _Unit4, "usp_UnitCode4_Delete");
            }
        }
    }

     
    类别重构完成,接下来,我们对UnitCode1.aspx.cs至UnitCode4.aspx.cs进行重构。因为这四个页面的类,也有很多相同的代码。重构之前,先创建一个页面的基类,暂叫它为BasePage,此类别继承了

     
    每个.aspx.cs继承刚才写的BasePage类,把InsusJsUtility objInsusJsUtility = new InsusJsUtility(); 这句拿掉,并移至BasePage中,根据继承的精神,它足够条件移了。



    移至BasePage之后,需要添加修饰符protected,这样每个.aspx.cs才可以访问得到。

    BasePage.cs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    /// <summary>
    /// Summary description for BasePage
    /// </summary>
    namespace Insus.NET
    {
        public class BasePage : System.Web.UI.Page
        {
            protected InsusJsUtility objInsusJsUtility = new InsusJsUtility();
        }
    }

     
    发现每个.aspx.cs代码,有两句重复了,需要删除。

     
    接下来,我们眼睛注意到每个.aspx.cs的Data_Binding()方法中,均有此一句:

    ((ISetValable)this.Master).SetValue("单位码X");


    因此Insus.NET把它封装入BasePage类中:

     
    然后在每个.aspx.cs中,拿掉((ISetValable)this.Master).SetValue("单位码X"); 这句,并改为如下图高亮语句。



    到此为止,Insus.NET暂停对.cs代码重构,转而看到Html代码。如下图中的插入记录代码,在四处个网页中每个.aspx都是相同的,因此Insus.NET对这些重构。

    对这部分的重构,只有创建用户控件(ascx),然后搬移过去,完成之后,再把这个用户控件拉至网页.aspx中:

    InsertForm.ascx
    <%@ Control Language="C#" AutoEventWireup="true" CodeFile="InsertForm.ascx.cs" Inherits="Sys_InsertForm" %>
    <table class="table">
        <tr class="tableRow">
            <td class="tableCell" style=" 35%;">单位码</td>
            <td class="tableCell">说明</td>
            <td style=" 12%; text-align: center;" class="tableCell">操作</td>
        </tr>
        <tr>
            <td class="tableCell">
                <asp:TextBox ID="TextBoxUnitCode" runat="server" CssClass="textbox" BackColor="#ffff6f"></asp:TextBox>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ControlToValidate="TextBoxUnitCode"
                    Display="none" ErrorMessage="单位码必须填写。" ValidationGroup="GeneralInsert"></asp:RequiredFieldValidator>
            </td>
            <td class="tableCell">
                <asp:TextBox ID="TextBoxDescription" runat="server" CssClass="textbox"></asp:TextBox>
            </td>
            <td style=" 12%;" class="tableCell">
                <asp:ValidationSummary ID="ValidationSummary1" runat="server" EnableClientScript="true"
                    ShowMessageBox="true" ShowSummary="false" ValidationGroup="GeneralInsert" />
                <asp:Button ID="ButtonCreate" runat="server" OnClick="ButtonCreate_Click" Text="创建"
                    ValidationGroup="GeneralInsert" />
            </td>
        </tr>
    </table>


    由于每个.aspx创建事件不一样,为了保持原有在.aspx.cs的事件,Insus.NET决定在用户控件中再public Click 事件。


    上图中,还写两个属性,分别是两个文本框的属性,这是为了让.aspx还能与用户控件的两个文本框的交互。

     用户控件重构好之后,当然需要拉至网页中去,有一个地方是需要注意的,在用户控件,还要写上OnClick事件,OnClick="ButtonCreate_Click":

     
    在.aspx.cs代码页中,一些代码需要异动,参考下图高亮位置:


     改程序,就得一步一个脚印,现在我们把目光放在每个.aspx的GridView控件上,它是显示记录,编辑记录以及删除等功能集成。有很高的相似度。只是Gridview的ID,DataKeyNames,以及OnRowEditing,OnRowCancelingEdit,OnRowUpdating,OnRowDeleting事件名称不一样,最后是绑定主键时,也不一样:

    <ItemTemplate>
         <%# Eval("UnitX") %>
    </ItemTemplate>


    这部分重构,相似度,但好象又很具有独立性,无法分开。现在Insus.NET决定对这些ID以及事件名改为一样。删除箭头所指的数字:

    改完之后,如下代码一样,Insus.NET只列了个网页,如Unitcode4(部分):

    <asp:GridView ID="GridViewUnitCode" runat="server" DataKeyNames="Unit4" AutoGenerateColumns="false" ShowHeader="false" CellPadding="2" CellSpacing="0" Width="100%" BorderWidth="1px" BorderColor="#c0c0c0" BorderStyle="solid"
                    HeaderStyle-Height="25" RowStyle-Height="25" HeaderStyle-BackColor="#efebde" OnRowEditing="GridViewUnitCode_RowEditing"
                    OnRowCancelingEdit="GridViewUnitCode_RowCancelingEdit" OnRowUpdating="GridViewUnitCode_RowUpdating"
                    OnRowDeleting="GridViewUnitCode_RowDeleting">
                    <Columns>
                        <asp:TemplateField>
                            <ItemStyle BorderStyle="solid" BorderWidth="1px" BorderColor="#c0c0c0" Width="35%" />
                            <ItemTemplate>
                                <%# Eval("Unit4") %>
                            </ItemTemplate>
                        </asp:TemplateField>


    当然在每个UnitCode1~3.aspx.cs的事件中,也应该修改,参考下图,把箭头的数据全删除。


    重名命重构,往往改动的地方都较多。全部改完之后,所有UnitCode1~4.aspx只差下图高亮位置的差异了:



    怎样解决这些差异,它是一个表字段,而且是主键。动态产生或是加载是否可行,想到了,行动就是了。在GridView中,去掉DataKeyNames="Unit1"属性。在显示ItemTemple中,改为一个标签,并为GridView添加一个事件 OnRowDataBound="GridViewUnitCode_RowDataBound"。



    在.aspx.cs中,添加一个变量,四个网页的变量值不同,分别为
    string _DataKeyName = "Unit1";
    string _DataKeyName = "Unit2";
    string _DataKeyName = "Unit3";
    string _DataKeyName = "Unit4";

    参考下面动画:

     
    程序经此一改,每个页面的html又一样了。所以我们可以把其中一页的GridView html代码块搬移至一个用户控件之内。创建一个用户控件:

    OperationForm.ascx
    <%@ Control Language="C#" AutoEventWireup="true" CodeFile="OperationForm.ascx.cs" Inherits="Sys_OperationForm" %>
    <asp:GridView ID="GridViewUnitCode" runat="server" AutoGenerateColumns="false" ShowHeader="false" CellPadding="2" CellSpacing="0" Width="100%" BorderWidth="1px" BorderColor="#c0c0c0" BorderStyle="solid"
        HeaderStyle-Height="25" RowStyle-Height="25" HeaderStyle-BackColor="#efebde" OnRowEditing="GridViewUnitCode_RowEditing"
        OnRowCancelingEdit="GridViewUnitCode_RowCancelingEdit" OnRowUpdating="GridViewUnitCode_RowUpdating"
        OnRowDeleting="GridViewUnitCode_RowDeleting" OnRowDataBound="GridViewUnitCode_RowDataBound">
        <Columns>
            <asp:TemplateField>
                <ItemStyle BorderStyle="solid" BorderWidth="1px" BorderColor="#c0c0c0" Width="35%" />
                <ItemTemplate>
                    <asp:Label ID="LabelUnitCode" runat="server" Text=""></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField>
                <ItemStyle BorderStyle="solid" BorderWidth="1px" BorderColor="#c0c0c0" />
                <ItemTemplate>
                    <%# Eval("Description") %>
                </ItemTemplate>
                <EditItemTemplate>
                    <asp:TextBox ID="TextBoxDescription" runat="server" Text='<%# Eval("Description") %>' CssClass="textbox"></asp:TextBox>
                </EditItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField>
                <ItemStyle BorderStyle="solid" BorderWidth="1px" BorderColor="#c0c0c0" Width="8%" />
                <ItemTemplate>
                    <asp:Button ID="ButtonEdit" runat="server" Text="编辑" CommandName="Edit" CausesValidation="false" />
                </ItemTemplate>
                <EditItemTemplate>
                    <asp:ValidationSummary ID="ValidationSummary2" runat="server" EnableClientScript="true"
                        ShowMessageBox="true" ShowSummary="false" ValidationGroup="GrieviewUpdate" />
                    <asp:Button ID="ButtonUpdate" runat="server" Text="更新" CommandName="Update" ValidationGroup="GrieviewUpdate" />
                    <asp:Button ID="ButtonCancel" runat="server" Text="取消" CommandName="Cancel" CausesValidation="false" />
                </EditItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="删除">
                <ItemStyle BorderStyle="solid" BorderWidth="1px" BorderColor="#c0c0c0" Width="4%" />
                <ItemTemplate>
                    <asp:Button ID="ButtonDelete" runat="server" Text="删除" CommandName="Delete" CausesValidation="false" />
                    <ajaxToolkit:ConfirmButtonExtender ID="ConfirmButtonExtender1" runat="server" TargetControlID="ButtonDelete"
                        ConfirmText="确认删除记录?">
                    </ajaxToolkit:ConfirmButtonExtender>
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>


    在OperationForm.ascx.cs中,需要处理几个问题,一是GridView的事件,主键,还是数据绑定的问题等。现在Insus.NET先解决GridView事件:
    宣告几个事件,除了GridViewUnitCode_RowDataBound(object sender, GridViewRowEventArgs e)无需处理,因为它与页没有任何交互,只是为GridView显示数据而已。

    Ok, 我们把用户控件拉至网页,并写好事件:

    下面是我们要解决主键,数据绑定,还有在GrieView显示主键的问题,在用户控件中,写一个只写属性,因为只需要为用户控件写入属性,不必为从用户控件获取值。

     private string _DataKeyName;
    
        public string DataKeyName
        {
            set { _DataKeyName = value; }
        }


    接下来,我们又需要去到每一个.aspx.cs中,为刚才的写好的属性赋值,你将看到下图高亮代码行,这样子,在每个网页运行时,就把网页的主键字符名称传至用户控件内。

     
    处理Gridview显示主键时,把下面的方法全搬至用户控件中,其余网页相同的事件删除。

     protected void GridViewUnitCode_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            if (e.Row.RowType != DataControlRowType.DataRow) return;
            var drv = e.Row.DataItem as DataRowView;
    
            if (e.Row.FindControl("LabelUnitCode") != null)
            {
                var lbl = e.Row.FindControl("LabelUnitCode") as Label;
                lbl.Text = drv[_DataKeyName].ToString();
            }
        }


    为了让.aspx.cs能与用户控件更好的交互,需要在站点创建一个接口:

    IGridViewControlable.cs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI.WebControls;
    
    /// <summary>
    /// Summary description for IGridViewControlable
    /// </summary>
    namespace Insus.NET
    {
        public interface IGridViewControlable
        {
            GridView GetGridViewControl();
        }
    }


    在用户控件OperationForm.ascx.cs实作它。


    在每一个.aspx.cs代码页中,写一个get属性:

    View Code
    GridView GridViewUnitCode
        {
            get
            {
                return ((IGridViewControlable)this.OperationForm1).GetGridViewControl();
            }
        }

     
    写到此,还没有完毕,精彩还在后头。我们再写一个基类,此基将为前面写好的两个用户控件继承。写用户控件的基类,跟页面的基类完全一样。看到否,这基类是继承了System.Web.UI.UserControl:


    基类写好,去分别打开以前写好的两个用户控件,继承这个用户控件的基类:


    然后把在InsertForm.ascx.cs中下面代码移至BaseUserControl.cs控件中:

     public event EventHandler Click;
    
        protected void ButtonCreate_Click(object sender, EventArgs e)
        {
            if (Click != null)
            {
                Click(this, e);
            }
        }


    相同的情况,把OperationForm.cs中下面代码也移至BaseUserControl.cs控件中,移至之后,需要在这个基类的用户控件中,引用命名空间 using System.Web.UI.WebControls;

    View Code
     public event GridViewEditEventHandler RowEditing;
        public event GridViewCancelEditEventHandler RowCancelingEdit;
        public event GridViewUpdateEventHandler RowUpdating;
        public event GridViewDeleteEventHandler RowDeleting;
    
        protected void GridViewUnitCode_RowEditing(object sender, GridViewEditEventArgs e)
        {
            if (RowEditing != null)
                RowEditing(sender, e);
        }
        protected void GridViewUnitCode_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
        {
            if (RowCancelingEdit != null)
                RowCancelingEdit(sender, e);
        }
        protected void GridViewUnitCode_RowUpdating(object sender, GridViewUpdateEventArgs e)
        {
            if (RowUpdating != null)
                RowUpdating(sender, e);
        }
        protected void GridViewUnitCode_RowDeleting(object sender, GridViewDeleteEventArgs e)
        {
            if (RowDeleting != null)
                RowDeleting(sender, e);
        }


    也就是说,当多用户控件中共用的属性,方法或是函数,也可以写在基类中。
    接下来,我们还看到每个.aspx.cs还在一段相同的代码:

    GridView GridViewUnitCode
        {
            get
            {
                return ((IGridViewControlable)this.OperationForm1).GetGridViewControl();
            }
        }


    Insus.NET也想把它移至基类BasePage.cs中去,直接cut and paste,它会提示找不到this.OperationForm1这个物件。不管怎样,出错就出错,移过去再说,其余的删除。解决问题,还是使用接口吧:

    IUserControlable
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    
    /// <summary>
    /// Summary description for IUserControlable
    /// </summary>
    namespace Insus.NET
    {
        public interface IUserControlable
        {
            UserControl GetUserControl();
        }
    }


    然后每个UnitCode1~4.aspx.cs均实作这个接口,下仅在一个类演示:

    我们打开BasePage基类,看下动画,很简单把刚才找不到物件的问题解决了:



    ok,此博文到此为止,望看过的网友,能从中学习或温习到继承知识,了解到类别与父类,网页与基类页,用户控件与用户控件基类,还有的是网页与用户控件之间的交互通讯等。
    最终重构好的程序,可以下载与博文开头的原程序对比。
    http://download.cnblogs.com/insus/ASPDOTNET/Ref_Org_inhert.rar

  • 相关阅读:
    Nginx 笔记(四)nginx 原理与优化参数配置 与 nginx 搭建高可用集群
    Nginx 笔记(三)nginx 配置实例
    Nginx 笔记(二)nginx常用的命令和配置文件
    Nginx 笔记(一)nginx简介与安装
    分布式事务专题笔记(三)分布式事务解决方案之TCC(三阶段提交)
    分布式事务专题笔记(二)分布式事务解决方案之 2PC(两阶段提交)
    分布式事务专题笔记(一) 基础概念 与 CAP 理论
    面试题: hashset如何保证值不会被重复的
    DSP 程序的执行时间
    DSP 中关键字extern,cregister,Near ,Far,restrict,volatile
  • 原文地址:https://www.cnblogs.com/insus/p/3029483.html
Copyright © 2020-2023  润新知