重構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="width: 35%;">單位碼</td>
        <td class="tableCell">說明</td>
        <td style="width: 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="width: 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM