在业务系统的开发过程中为了保证页面风格的一致性以及减少重复代码的编写我们需要引入基类页的概念即定义一个基类页让所有 的页面都继承这个基类并在该基类页中加入公用的属性和方法
实际使用时按照功能页面划分可以定义多个基类页如
class FormBase
class BizFormBase FormBase
class ViewFormBase : BizFormBase
class EditFormBase : BizFormBase
class QueryFormBase : FormBase
FormBase基类页中的根提供与业务无关的服务如URL重写日志等
BizFormBase加入和业务相关的属性如该 页面的当前业务对象ID等
ViewFormBaseEditFormBase实现具体的查看编辑功能
QueryFormBase 实现对通用查询页面的封装
从面向对象的角度看基类页与普通的基类继承类设计其实区别并不大都要在基类中编写公用的属性方法并通过虚函数事件等方式让继承类重写或响 应所不同的是基类页的设计过程受到所在环境的约束在WinForm环境下我们可以预先定义好窗体的公用元素如工具条默认的表格以及 DataSource控件等而到了下的WebForm则无法实现界面一级的继承同时加入了状态管理等要求
为了帮助大家理解我们以查询基类页的设计过程来分析
一个最简单的查询页面会包括三部分多个查询条件文本框查询按钮以及表格同时查询页会和一个数据访问组件关联当点查询时会把查询条件转成 where语句提交给数据访问组件
QueryPeopleForm
OnQueryButtonClick()
{
string peopleName = txtPeopleNameText;
string peopleAge = txtPeopleAgeText;
string sql;
sql = stringFormat(Name Like%{}%and Age = {} PeopleName peopleAge);
PeopleManager manager = new PeopleManager();
thisgridMainDataSource = managerGetDataTable(sql);
thisgridMainDataBind();
}
当点击查询按钮时我们做了以下三件事
获取查询条件
提交查询
将查询结果绑定到表格
这儿的提交查询和绑定在不同的查询页面都是一样的于是我们首先把放到基类页中并提供这样一个方法void QueryAndBind(IManager manager string sql);这儿要定义IManager接口让所有的Manager都实现该接口这样基类页就无需知道具体的Manager只要调用 IManagerGetDataTable方法然后绑定表格到即可
使用基类页后的代码
QueryPeopleForm : QueryFormBase
OnQueryButtonClick()
{
string peopleName = txtPeopleNameText;
string peopleAge = txtPeopleAgeText;
sql = stringFormat(Name Like%{}%and Age = {} PeopleName peopleAge);
QueryAndBind(new PeopleManager() sql);
}
这儿的代码少了但仍有问题当查询条件变化后每次拼查询语句的工作即枯燥又容易出错那么我们加入一个Query类以简化这儿的操作:
public enum QueryOperator
{
//等于比较
Equal =
// 不等于
NotEqual =
// Like比较
Like =
}
class Query
{
void Add(string fieldName string value QueryOperator oper);
string GetSql();
}
QueryPeopleForm : QueryFormBase
OnQueryButtonClick()
{
Query query = new Query();
queryAdd(Name txtPeopleNameText QueryOperatorLike);
queryAdd(Age txtPeopleAgeText QueryOperatorEqual);
QueryAndBind(new PeopleManager() queryGetSql());
}
把拼Sql的工作放在Query类中做调用者只要声明查询字段对应的值和比较类型即可
到这一步我们的基类页已经很好用了但还有一个小问题也就是前面说的在WebForm中无法实现界面级的继承那么基类页的 QueryAndBind方法将无法知道查询结果要绑定到哪一个表格这时我们的做法是在基类页中声明DefaultGrid属性让继承页来告知当前 的表格控件
修改后的代码
QueryPeopleForm : QueryFormBase
OnQueryButtonClick()
{
InitControls(gridMain);
Query query = new Query();
queryAdd(Name txtPeopleNameText QueryOperatorLike);
queryAdd(Age txtPeopleAgeText QueryOperatorEqual);
QueryAndBind(new PeopleManager() queryGetSql());
}
至此基类页的功能已经完整了但仍然不够如果我们以后想改变查询按钮点击的行为比如查询结果为空时要弹出对话框提示这时仍然要到处修改页 面代码这不是我们所希望的于是我们将QueryButton的OnClick操作也放在基类页了中执行继承页只要初始化数据访问组件和设置查询条件 即可
QueryPeopleForm : QueryFormBase
void Initialize()
{
// 指定页面对应的Manager
Manager = new PeopleManager();
// 绑定控件
InitControls(gridMain btnQuery);
}
void GetQueryInfo(Query query)
{
//获得查询条件
queryAdd(Name txtPeopleNameText QueryOperatorLike);
queryAdd(Age txtPeopleAgeText QueryOperatorEqual);
}
QueryFormBase:
private IManager manager = null;
public IManager Manager
{
get { return manager; }
set { manager = value; }
}
void InitControls(GridView grid Button queryButton)
{
thisdefaultGrid = grid;
thisqueryButton = queryButton;
queryButtonClick += new EventHandler(QueryButton_Click);
}
void QueryButton_Click(object sender EventArgs e)
{
Query query = new Query();
GetQueryInfo(Query);
QueryAndBind(manager queryGetSql());
}
总的代码可以从附件中下载大家可以加入断点看看基类继承类页的代码执行顺序
应该说基类的设计相对复杂但好处是继承页的代码变得清 楚了没有多余重复的代码
而基类页的设计其实是有技巧的总结起来有以下几条
首先以最直接的方式写出页面代码
提取公用方法和添加辅助类
提取事件处理流程到基类页中
在基类页中设计需要继承页重载的方法与事件
从设计上来讲用基类页的方式来统一操作简化页面代码是一种非常直观的方式缺点是随着项目的演化基类页会变得大而全不容易被新的项目重用 这时我们就可以考虑把其中的一部分功能放到用户控件和自定义组件中来实现以减少耦合性和提高重用性