(绝对原创)三层式的层次划分

三层式开发中的层次划分讨论

先举一个曾经在哪本书上看到的例子:现在你想在 1 米宽的小溪上建一座桥,你会在上面放块木板就完了。如果想在宽一点的小河上建这桥,你就需要计算木材用料,价格等,如果需要别人帮忙,你还要多一些图纸什么的让别人理解你的想法。现在你要在大江上面建桥,你需要有整体的计划,包括各个方面,比如将来可能的收费和利益分配等问题。

这里讲 3 层式,其实是针对“大江上面建桥”来的,对于 1 米宽的小溪,在实际中可能一点用都没有。不过现在我不可能去拿个长江大桥作例子来讲,所以这里还是用这条简单的小溪,讲讲怎么建桥。之所以讲这么多废话,是为了防止部分人看完此文之后“小小一个东西,搞那么麻烦干什么。。”其实这里讲的不是具体的这个例子,而是分层的思想,理解这点非常重要。

下面我就我们大家日常见最多的例子来讲,就是“用户登录”的例子。这个例子很简单,但是麻雀虽小五脏俱全。从数据访问到业务规则到界面全有了。

本文分 2 个部分,如果只想研究面向对象的思想,对实现已经熟悉,可以跳过第一部分。

第一部分

新建一个空白解决方案。然后:

“添加”-“新建项目”-“其他项目”-“企业级模版项目”-“ C# 生成块”-“数据访问”(数据层,下简称 D 层)

“添加”-“新建项目”-“其他项目”-“企业级模版项目”-“ C# 生成块”-“业务规则”(业务层,下简称 C 层)

“添加”-“新建项目”-“其他项目”-“企业级模版项目”-“ C# 生成块”-“ Web 用户界面”(界面层,下简称 U 层)

右键点“解决方案”-“项目依赖项”,设置 U 依赖于 D 、 C , C 依赖于 D 。

对 U 添加引用 D 、 C ,对 C 添加引用 D 。

到此为止,一个三层的架子建立起来了。我上面说的很具体很“傻瓜”,知道的人觉得我废话,其实我这段时间很强烈的感觉到非常多的人其实对这个简单的过程完全不了解。虽然不反对建 2 个“空项目”和 1 个“ Asp net Web 应用程序项目”也可以作为 3 层的框架,而且相当多的人认为其实这些“企业级模板项目”其实就是个空项目,这是一个误区。没错,企业级模板项目你从解决方案资源管理器里看它是个什么也没有的,但是你可以用记事本打开项目文件,看见不同了吧??有些东西在背后,你是看不见的,不过系统已经做好了。也就是说,如果你在 C 层里的某个类里“ using System Data SqlClineit ”,或者使用一个 SqlConnection 对象,编译时候不会出错,但是会在“任务列表”里生成一些“策略警告”,警告你在 C 层里不要放应该放在 D 层的东西(虽然就程序来说没错,但是可读性可维护性就打了折扣)而这种功能,空项目是无法給你的。

我们知道建桥需要砖块,应该是先准备好砖再来建桥,不过为了讲解上的顺序性和连贯性,简单性。我们先建桥,建的过程中需要砖块再现做,这样就不会多出来“桥不需要的东西”。注意在实际中,还是应该先准备砖块。

U 层其实就是桥, C 层是砖块, D 层是原料(石头、沙子)。这也解释前面为什么 U 层要引用、依赖 D 层(而不是 U 对 C , C 对 D 的层次),因为桥除了需要砖头,其实也需要石头沙子。

我们在 U 层建一个 Login aspx (这里插入一句,我不喜欢去把系统自动生成的 WebForm1 aspx 拿来改成 login 或 index 或直接删除,我一般留着它当测试代码用,等到整个系统冻结再把它移除就可以了。)添加 1 个 TextBox ( id=txt ),一个 DropDownList ( id=ddl ),一个 Button(id=btn) 。其中 DropDownList 用来选择用户名, button 是提交按钮, TextBox 用来输入密码。

现在我们必须要添加的代码分为 2 部分: 1 、 Page_load 时对 ddl 的初始化。 2 、 btn 的 click 处理。

1 :

private void Page_Load(object sender, System.EventArgs e)

{

if(!IsPostBack)

{

this.ddl.DataSourse=DataManager.GetOneColunm( “ User ” , ” uid ” ); //讲解1

this.ddl.DataBind();

}

}

2:

private void Btn_Click(object sender, System.EventArgs e)

{

string uid=this.ddl.SelectedValue;

string psw=this.txt.Text;

if(psw = ”” )

MessageBox( “ 空密码! ” );

else

{

User theUser;

try

{

theUser=new User(uid); //讲解2

}

catch(Exception e)

{

MessageBox(e. Message);//讲解2

return;

}

if(theUser.CheckPsw(psw)) //讲解3

{

theUser.SetSessions();

Response.Redirect( “…………… .. ” ); //登录成功!

}

else

{

MessageBox( “ 密码错误! ” );

}

}

}

讲解 1: DataManager 是 D层中的一个类,提供常见的数据操作。 GetOneColunm(string Table,string Colunm) 方法返回一个只有 1列的DataTable,值为数据库中表名为Table,的Colunm列。

public class DataManager

{

public DataManager()

{

}

public static DataTable GetOneColunm(string Table,string Colunm)

{

//此处省略相关代码。返回指定表指定列

}

}

其实这个地方演示的是在 U层直接绕过C层访问D层的例子,因为该结构逻辑上很简单,而且获取用户名并不是现实社会中的业务逻辑的一部分(仅仅是界面需要,因为在这里其实用成2个TextBox的话完全不需要这一步)

讲解 2:定义一个User类的实例。User类的定义可能如下:

public class User

{

public User(string uid)

{

if(DataManager.IsIn( “ user ” , ” uid= ’ "+uid+ ”’” ))

throw "用户不存在";

else
//User()其他初始化;

}

public bool CheckPsw(string psw)

{

if(DataManager.IsIn( “ user ” , ” uid= ’ "+uid+ ”’ and psw= ’” +psw+ ”’” ))

return true;

else

return false;

}

}

注意到用户类构造函数中用了个 throw来抛出用户不存在的异常,在下面catch的时候用 MessageBox(e. Message); 来弹出“用户不存在”的错误。这里其实也是为了演示一个层间传递信息的手段,异常也是一种手段,虽然在这里其实可以有其他方式比如返回值,引用参数之类的直接用一个方法来获得用户是否存在的信息,没必要放在构造里,我这么做只是为了演示传递过程,在后面的有讨论这种用法在分层模式下某种特殊情况的应用以解决一些问题。这个类里又用了 DataManager类的一个静态方法IsIn(string Table,string str)该方法其实其实是执行 “ select * from Table where str ”

这个 Sql语句并在返回空的时候方法返回false,否则返回true。一个很简单的方法。

Published At
Categories with Web编程
Tagged with
comments powered by Disqus