浅尝三层架构
2009-03-07 09:35 yearN 阅读(685) 评论(6) 收藏 举报三层架构
在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。微软推荐的分层式结构一般分为三层,从下至上分别为:数据访问层(Data Access Layers )、业务逻辑层(Business Logic Layers)(又或成为领域层)、表示层(User Interface)。
一个公司的结构:

假如销售人员接了一个订单,那么他就会直接把这个信息传给管理层,由管理层规划如何完成这个订单,等管理层的决策定了,工人就会按照管理层的要求,去生产这个订单。
在这个流程中,销售人员的工作就相当于我们三层架构中的表示层(UI),而管理层就是我们的业务逻辑层(BLL)了,工人自然是我们的数据访问层(DAL),机器|车床也就是数据库(DB)。
在此,我们对三层架构有一个总休的认识了,下面看一下,我们初学者经常对三层架构的误解:
n 比如有些初学者以为,DBServer-WebServer-Client(简单地放置三台机器)是三层架构,其实这是物理意思上的三层架构,和程序的三层架构没有什么关系。
n 还有人以为,WinForm界面的窗体或者WebForm的aspx是最上一层,它们对应的代码后置(codebehind)文件Form.cs或aspx.cs是第二层,然后再有一个访问数据库的代码,比如ado.cs或SqlHelper.cs是最下一层,这其实也是非常错误的理解。
n 再有,很多人认为MVC模式(Model-View-Controler)就是三层架构,这是比较经典的错误理解了。
先看一张结构图:

1. 数据访问层:
n 功能描述:处理与数据库之间的交互,不应对数据做任何业务上的加工。捕获数据库交互式出现的异常,抛出或记录下来。
n 说明:它的作用就是数据访问,如果你没有用其他的类似于ORM的框架,那么这里应该是SQL语句集合地(或者你可以把SQL语句写在存储过程中),业务逻辑层和表示层绝对不能出现SQL语句(包括SQL的关键字,单引号、百分号、LIKE等都不能出现)。
数据访问层主要是对原始数据(数据库或者文本文件等存放数据的形式)的操作层,而不是指原始数据,也就是说,是对数据的操作,而不是数据库,具体来说就是为业务逻辑层或表示层提供数据服务。
2.业务逻辑层:
n 功能描述:接受从表示层传过来的数据,做业务上的数据校验,并实现业务流程,最后,把加工后的数据传给数据访问层。
n 说明:你可以认为在三层之间有两堵墙,三层之间谁也看不见谁,我只做好我的本职工作,其他的事情我不关心。业务逻辑层应该是设计者最关注的地方,也是设计模式应用最广泛的地方,业务逻辑层设计的关键就是尽量的实现松耦合,如果业务逻辑层中的各个类之间都有调用关系,那这就是一个很糟糕的设计。进一步来说,如果把这些松耦合的功能模块的接口作为一种服务的模式(比如Web Service)发布出去,OK,这就是SOA。
业务逻辑层主要是针对具体的问题的操作,也可以理解成对数据层的操作,对数据业务逻辑处理,如果说数据层是积木,那逻辑层就是对这些积木的搭建。
3.表示层:
n 功能描述:从用户控件中取得数据或者从业务逻辑层取得数据后展现出来,不应对取得的数据做任何加工。
n 说明:在这层要是出现SQL语句那就更不应该了。在WEB项目中,因为效率的原因,很多时候要在客户端做一些必填项的验证(其实这也是业务逻辑的一部分),但这是值得的。
表示层主要表示WEB方式,也可以表示成WINFORM方式,WEB方式也可以表现成:aspx, 如果逻辑层相当强大和完善,无论表现层如何定义和更改,逻辑层都能完善地提供服务。
说了这么多,还是看一下简单的代码吧:
/// <summary>
/// 实体类
/// </summary>
public class UserInfo
{
public UserInfo() { }
#region Model
private string _username; //用户名
private string _password; //密码
//
//...
//
/// <summary>
/// 用户名
/// </summary>
public string UserName
{
set { _username = value; }
get { return _username; }
}
/// <summary>
/// 密码
/// </summary>
public string PassWord
{
set { _password = value; }
get { return _password; }
}
//
//...
//
#endregion Model
}
/// <summary>
/// 数据访问类
/// </summary>
class UserDAL
{
//很多人最闹不清的就是数据访问层,到底那部分才算数据访问层呢?
//有些认为数据库就是数据访问层,这是对定义没有搞清楚,
//DAL是数据访问层而不是数据存储层,因此数据库不可能是这一层的。
//也有的把SQLHelper(或其同类作用的组件)作为数据访问层,它又是一个可有可无的东西,
//SQLHelper的作用是减少重复性编码,提高编码效率,
//因此如果我习惯在乎效率或使用一个非数据库的数据源时,
//可以丢弃SQLHelper,一个可以随意弃置的部分,又怎么能成为三层架构中的一层呢。
//可以这样定义:与数据源操作有关的代码,就应该放在数据访问层中,属于数据访问层
public IList<UserInfo> SelectUsers() { return null; }//:返回所有的用户信息列表
public UserInfo SelectUser(int UserId) { return null; }//:返回指定用户的相信信息
public bool InsertUser(UserInfo User) { return true; }//:新增用户信息
public bool UpdateUser(UserInfo User) { return true; }//:更新用户信息
public void DeleteUser(int UserId) { }//:移除用户信息
}
/// <summary>
/// 简单业务逻辑
/// </summary>
class UserBLL
{
//专门用来处理与业务逻辑有关的操作。可能有很多人觉得这一层唯一的用途,
//就是把表现层传过来的数据转发给数据层。这种情况确实很多,
//但这只能说明项目比较简单,
//或者项目本身与业务的关系结合的不紧密(比如当前比较流行的MIS),
//所以造成业务层无事可做,
//只起到了一个转发的作用。但这不代表业务层可有可无,
//随着项目的增大,或者业务关系比较多,
//业务层就会体现出它的作用来了。
//此处最可能造成错误的,就是把数据操作代码划在了业务逻辑层,
//而把数据库作为了数据访问层。
//例如:SelectUser(UserInfo userInfo);IsExist(UserInfo userInfo);
//例如:多表操作(插入,更新。。。)
public IList<UserInfo> GetUsers() { return null; }//返回所有的用户信息列表
public UserInfo GetUser(int UserId) { return null; }//返回指定用户的详细信息
public bool AddUser(UserInfo User) { return true; }//新增用户信息
public bool ChangeUser(UserInfo User) { return true; }//更新用户信息
public void RemoveUser(int UserId) { }//移除用户信息
}
判定三层架构的标准:
将三层中的任意一层完全替换,都不会对其它两层造成影响,这样的构造基本就符合三层标准了(虽然实现起来比较难^_^)。例如如果将项目从B/S改为C/S(或相反),那么除了UI以外,BLL与DAL都不用改动;或者将SQLServer改为Oracle,只需替换SQLServerDAL到OracleDAL,无需其它操作等等。
具体的区分方法:
n 数据数据访问层:主要看你的数据层里面有没有包含逻辑处理,实际上他的各个函数主要完成各个对数据文件的操作。而不必管其他操作。
n 业务逻辑层:主要负责对数据层的操作。也就是说把一些数据层的操作进行组合。
n 表示层:主要对用户的请求接受,以及数据的返回,为客户端提供应用程序的访问。
n
为什么要分三层:
我们用三层结构主要是使项目结构更清楚,分工更明确,有利于后期的维护和升级。它未必会提升性能,因为当子程序模块未执行结束时,主程序模块只能处于等待状态。这说明将应用程序划分层次,会带来其执行速度上的一些损失。但从团队开发效率角度上来讲却可以感受到大不相同的效果。
n 不分层也就是说所有实现都在页面代码内实现,这样的程序将导致单个文件或单个类的代码量极大,出现BUG你最好的方式就是设置断点并跟踪。而且工作人员离职,下一个接班人也比较头大。
n 分层后整个结构十分清晰,出现错误后你马上就能反映到这是哪里出的问题。而且,随着经验的增加,一个成熟的框架能够帮你解决更多的问题。
分层的优点:
n 开发人员可以只关注整个结构中的其中某一层;
n 可以很容易的用新的实现来替换原有层次的实现;
n 可以降低层与层之间的依赖;
n 有利于标准化;
n 利于各层逻辑的复用。
分层的缺点:
n 降低了系统的性能。这是不言而喻的。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成。
n 有时会导致级联的修改。这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码。
总结:
不要因为某个层对你来说没用,或者实现起来特别简单,就认为它没有必要,或者摒弃它,或者挪作它用。只要进行了分层,不管是几层,每一层都要有明确的目的和功能实现,而不要被实际过程所左右,造成同一类文件位于不同层的情况发生。也不要出现同一层实现了不同的功能的情况发生。
说明:
本文主要参考园子里的大侠们的文章,有解释不到位的地方还请指正。
浙公网安备 33010602011771号