这里我讲解如何充分发挥母版页的优势。关于母版页的优点有大量的文章进行说明,参看 http://www.odetocode.com/Articles/450.aspx 此文当然和那些文章不相同。有时,你会经常碰到这样的场景:相同的用户界面(GUI),但是不同的业务逻辑,如图所示。因此,你会考虑使用用户控件来保持各个页面的标准外观。但如果你听我说明一下如何使用工厂模式设计的母版页,你就会感觉酷毙了!这里我使用了带单击功能的表格(Grid)。

背景
阅读此文之前你必须对母版页的相关知识有所了解,这样你能更好的理解此文
工作流程
当用户从菜单中选择订单详情时,父表格将会填充所有订单列表,子表格将会填充包含在此订单的产品列表。当用户选择职员时,父表格将会填充所有职员列表,子表格将会填充选中职员的地区列表。有2个内容页来显示选中项的相关信息。
关于代码
下载的代码包括dbcontroller1 helper类。你只需修改数据库链接字符串来链接到你的SQL server就可以了。后台数据库是SQL server自带的Northwind数据库。
概述
此应用程序包括一个母版页,其中有1个菜单控件和2个表格控件(父表格和子表格),其中子表格的数据源依赖父表格。
我们首先看看Northwind数据库中订单和订单明细表的例子。我们在父表格中填充订单列表,当选中其中一个订单时,子表格填充该订单包括的产品列表。这个场景同样适用于职员和职员地区的案例。同样,在应用程序中经常有类似的场景。你准备怎么做?创建大量独立的类似的页面?还是创建一个用户控件?尽管用户控件是个不错的选择,但这里我们用母版页来实现这个需求。
在进一步讲解之前,我们先来了解一下工厂模式到底是什么?
工厂方法
工厂方法(FactoryMethod)模式是类的创建模式,其用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中(GOF)。在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不接触哪一个产品类被实例化这种细节。这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。
这就是我们所期望的。下图解释了参数化工厂方法。工厂方法消除了代码中和特定应用程序相关的类,代码仅仅定义了基类接口,因此它可以和与基类具有同样的接口的用户定义的类配合工作。

实现工厂方法
我们创建一个抽象类Base,其中包括了4个抽象方法。Order 和 Employee类继承抽象类Base。下面是Base类的代码。BindParentGrid将把Parent数据源绑定到父表格中,Parent数据源既可以是Order列表,也可以是Employee列表,这看用户的选择了。BindChildGrid方法Child数据源(产品或者地区)绑定到子表格中。getParentData返回Parent数据源信息,getChildData返回子数据源信息。Key是父表格传递给方法的参数。
我们从抽象类继承过来两个类BIOrderMaster 和 BIEmployeeMaster,来控制表格绑定。下面是其中一个继承类的代码。我们不再讨论数据访问组件,详细情况请直接看附件代码。///<summary> /// 抽象类 ///</summary> public abstract class Base { public abstract void BindParentGrid(DataDigest.WebControls.GridView gvParent); public abstract void BindChildGrid(DataDigest.WebControls.GridView gvChild, string ParentId); public abstract DataSet getParentData(); public abstract DataSet getChildData(string Key); }
无论何时用户从菜单中选择一个特定的项时,我们把页标识(page identity)存到Session中。母版页把页标识传给工厂类,工厂类返回匹配的基类类型的对象。我们的具体类 BIOrderMaster 和 BIEmployeeMaster 具有相同的类型,因为他们共享基类的接口。我们的工厂类如下所示:///<summary> /// 具体类 ///</summary> public class BIOrderMaster : Base { private DAccessOrder Orders = newDAccessOrder(); private DataSet dsParent = newDataSet(); public BIOrderMaster() { dsParent = Orders.getOrders(); } public override void BindParentGrid(DataDigest.WebControls.GridView gvParent) { if (dsParent == null) { dsParent = Orders.getOrders(); } string[] key = newstring[1]; key[0] = "OrderID"; gvParent.DataSource = null; gvParent.Columns.Clear(); gvParent.DataSource = dsParent; gvParent.DataKeyNames = key; BoundField TtlCoNm = newBoundField(); TtlCoNm.DataField = "OrderID"; TtlCoNm.HeaderText = "Order ID"; gvParent.Columns.Add(TtlCoNm); TtlCoNm.ItemStyle.Width = 600; gvParent.DataBind(); } public override void BindChildGrid(DataDigest.WebControls.GridView gvChild, string ParentId) { string[] key = newstring[1]; key[0] = "ProductID"; DataSet dsChild = Orders.getProducts(ParentId); gvChild.SelectedIndex = -1; gvChild.DataSource = null; gvChild.Columns.Clear(); gvChild.DataSource = dsChild; gvChild.DataKeyNames = key; BoundField BrName = newBoundField(); BrName.DataField = "ProductName"; BrName.HeaderText = "Product Name"; gvChild.Columns.Add(BrName); BrName.ItemStyle.Width = 600; gvChild.DataBind(); } public override DataSet getParentData() { return dsParent; } public override DataSet getChildData(string Key) { return Orders.getProducts(Key); } }
工厂类
///<summary> /// 返回实现抽象基类的对象 ///</summary> public class Factory { public Factory() { } public Base GetObject(string type) { Base objbase = null; switch (type) { case "Order Detail": objbase = newBIOrderMaster(); break; case "Employee Territorie": objbase = newBIEmployeeMaster(); break; default: throw new Exception("Unknown Object"); } return objbase; } }