实战剖析三层架构1

实战剖析三层架构1
[转]实战剖析三层架构1 
摘自:笨笨的熊窝
原文地址:http://www.cnblogs.com/benbenkoala/archive/2008/10/31/1209658.html
   引言:本文不是从理论的角度来探讨三层架构,而是用一个示例来介绍如何建设一个三层架构的项目,并说明项目中各个文件所处的层次与作用。写本文的目的,不是为了说明自己的这个方法有多对,别人的肯定不对,而是希望给那些初学三层架构却不知从何入手的朋友提供一点帮助。因为网上的文章,大多是注重理论的介绍,而忽略了具体的实践应用,或者有示例但讲得不透彻。导致看了之后,理论上又学习了一遍,但还是不知道代码怎么写。所以想从这个方面入手写一下,让从来没做过三层架构的初学者也能照猫画虎,写出代码来。文章表述的是笔者个人对三层架构的认识,肯定有许多不足的地方,欢迎大家指正,小弟也会根据反馈来修改这篇文章。文中的代码是伪代码,仅用来阐明思路。
    正文:
    一提三层架构,大家都知道是表现层( UI ),业务逻辑层( BLL )和数据访问层( DAL ),而且每层如何细分也都有很多的方法。但具体代码怎么写,到底那些文件算在哪一层,却是模模糊糊的。下面用一个简单的例子来带领大家实战三层架构的项目,这个例子只有一个功能,就是用户的简单管理。
    首先建立一个空白解决方案,添加如下项目及文件
    1 、添加 ASP.NET Web Application 项目,命名为 UI ,新建 Web Form 类型文件 User.aspx (含 User.aspx.cs
    2 、添加 ClassLibrary 项目,命名为 BLL ,新建 Class 类型文件 UserBLL.cs
   
3 、添加 ClassLibrary 项目,命名为 DAL ,新建 Class 类型文件 UserDAL.cs 。添加 SQLHelper 引用。(这个是微软的数据访问类,也可以不用,直接编写所有的数据访问代码。我一般用自己写的数据访问类 DataAccessHelper )。
    4 、添加 ClassLibrary 项目,命名为 Model ,新建 Class 类型文件 UserModel.cs
    5 、添加 ClassLibrary 项目,命名为 IDAL ,新建 Interface 类型文件 IUserDAL.cs
    6 、添加 ClassLibrary 项目,命名为 ClassFactory
    相信大家已经看出来了,这个和 Petshop 的示例没什么区别,而且更简单,因为在下也是通过 Petshop 学习三层架构的。但一些朋友对于这几个项目所处的层次,以及它们之间的关系,可能比较模糊,这里逐个说明一下:
    1 User.aspx User.aspx.cs
    这两个文件(以及文件所属的项目,下面也是如此,不再重复强调了)都属于表现层部分。 User.aspx 比较好理解,因为它就是显示页面了。 User.aspx.cs 有些人觉得不应该算,而是要划到业务逻辑层中去。如果不做分层的话,那么让 User.aspx.cs 来处理业务逻辑,甚至操作数据库都没什么问题,但是做分层的话,这样就不应该了。在分层结构中, User.aspx.cs 仅应该处理与显示有关的内容,其它部分都不应该涉及。
    举例:我们实现用列表方式显示用户的功能,那么提取信息的工作是由 BLL 来做的, UI (本例中是 User.aspx.cs )调用 BLL 得到 UserInfo 后,通过代码绑定到 User.aspx 的数据控件上,就实现了列表的显示。在此过程中 User.aspx.cs UI 没有起到什么作用,仅是用来传递数据,而且因为实际编码中大部分情况都是如此的实现,所以使有些人觉得 User.aspx.cs 不应该算 UI ,而应该并入 BLL 负责逻辑处理。继续往下看,这时提出了一个新需求,要求在每个用户的前面加一个图标,生动地表现出用户的性别,而且不满 18 岁的用儿童图标表示。这个需求的实现,就轮到 User.aspx.cs 来做了,这种情况下 User.aspx.cs 才算有了真正的用途。
    2 NewBLL.cs
    添加如下方法:
    public IList<UserInfo> GetUsers() :返回所有的用户信息列表
    public UserInfo GetUser(int UserId) :返回指定用户的详细信息
    public bool AddUser(UserInfo User) :新增用户信息
    public bool ChangeUser(UserInfo User) :更新用户信息
    public void RemoveUser(int UserId) :移除用户信息
    此文件就属于业务逻辑层了,专门用来处理与业务逻辑有关的操作。可能有很多人觉得这一层唯一的用途,就是把表现层传过来的数据转发给数据层。这种情况确实很多,但这只能说明项目比较简单,或者项目本身与业务的关系结合的不紧密(比如当前比较流行的 MIS ),所以造成业务层无事可做,只起到了一个转发的作用。但这不代表业务层可有可无,随着项目的增大,或者业务关系比较多,业务层就会体现出它的作用来了。
    此处最可能造成错误的,就是把数据操作代码划在了业务逻辑层,而把数据库作为了数据访问层。
    举例:有些朋友感觉 BLL 层意义不大,只是将 DAL 的数据提上来就转发给了 UI ,而未作任何处理。看一下这个例子
    BLL
    SelectUser UserInfo userInfo )根据传入的 username email 得到用户详细信息。
    IsExist UserInfo userInfo )判断指定的 username email 是否存在。
    然后 DAL 也相应提供方法共 BLL 调用
    SelectUser UserInfo userInfo
    IsExist UserInfo userInfo
    这样 BLL 确实只起到了一个传递的作用。
   
但如果这样做:
    BLL.IsExist Userinfo userinfo
    {
          UerInfo user = DAL.SelectUser User );
       
return (userInfo.Id != null); 
    }
    那么 DAL 就无需实现 IsExist() 方法了, BLL 中也就有了逻辑处理的代码。
    3 UserModel.cs
    实体类,这个东西,大家可能觉得不好分层。包括我以前在内,是这样理解的: UI ß à Model ß à BLL ß à Model ß à DAL ,如此则认为 Model 在各层之间起到了一个数据传输的桥梁作用。不过在这里,我们不是把事情想简单,而是想复杂了。
    Model 是什么?它什么也不是!它在三层架构中是可有可无的。它其实就是面向对象编程中最基本的东西:类。一个桌子是一个类,一条新闻也是一个类, int string doublie 等也是类,它仅仅是一个类而已。
    这样, Model 在三层架构中的位置,和 int string 等变量的地位就一样了,没有其它的目的,仅用于数据的存储而已,只不过它存储的是复杂的数据。所以如果你的项目中对象都非常简单,那么不用 Model 而直接传递多个参数也能做成三层架构。
    那为什么还要有 Model 呢,它的好处是什么呢。下面是思考一个问题时想到的,插在这里:     
    Model
在各层参数传递时到底能起到做大的作用?
    在各层间传递参数时,可以这样:
    AddUser userId userName userPassword ,)
    也可以这样:
    AddUser userInfo
    这两种方法那个好呢。一目了然,肯定是第二种要好很多。
    什么时候用普通变量类型( int,string,guid,double )在各层之间传递参数,什么使用 Model 传递?下面几个方法:
   
SelectUser int UserId
    SelectUserByName string username
    SelectUserByName string username string password
    SelectUserByEmail string email
   
SelectUserByEmail string email string password
    可以概括为:
    SelectUser userId
    SelectUser user
    这里用 user 这个 Model 对象囊括了 username password email 这三个参数的四种组合模式。 UserId 其实也可以合并到 user 中,但项目中其它 BLL 都实现了带有 id 参数的接口,所以这里也保留这一项。 
    传入了 userInfo ,那如何处理呢,这个就需要按照先后的顺序了,有具体代码决定。
    这里按这个顺序处理
    首先看是否同时具有 username password ,然后看是否同时具有 email password ,然后看是否有 username ,然后看是否有 email 。依次处理。
    这样,如果以后增加一个新内容,会员卡( number ),则无需更改接口,只要在 DAL 的代码中增加对 number 的支持就行,然后前台增加会员卡一项内容的表现与处理即可。 
    4 UserDAL.cs
    public IList<UserInfo> SelectUsers() :返回所有的用户信息列表
    public UserInfo SelectUser(int UserId) :返回指定用户的相信信息
    public bool InsertUser(UserInfo User) :新增用户信息
    public bool UpdateUser(UserInfo User) :更新用户信息
    public void DeleteUser(int UserId) :移除用户信息
    很多人最闹不清的就是数据访问层,到底那部分才算数据访问层呢?有些认为数据库就是数据访问层,这是对定义没有搞清楚, DAL 是数据访问层而不是数据存储层,因此数据库不可能是这一层的。也有的把 SQLHelper (或其同类作用的组件)作为数据访问层,它又是一个可有可无的东西, SQLHelper 的作用是减少重复性编码,提高编码效率,因此如果我习惯在乎效率或使用一个非数据库的数据源时,可以丢弃 SQLHelper ,一个可以随意弃置的部分,又怎么能成为三层架构中的一层呢。
    可以这样定义:与数据源操作有关的代码,就应该放在数据访问层中,属于数据访问层
    5 IUserDAL
    数据访问层接口,这又是一个可有可无的东西,因为 Petshop 中带了它和 ClassFactory 类工厂,所以有些项目不论需不需要支持多数据源,都把这两个东西做了进来,有的甚至不建 ClassFactory 而只建了 IDAL ,然后“ IUserDAL iUserDal = new UserDAL(); ”,不知意义何在。这就完全是画虎不成反类犬了。
   
许多人在这里有一个误解,那就是以为存在这样的关系: BLL ß à IDAL ß à DAL ,认为 IDAL 起到了 BLL DAL 之间的桥梁作用, BLL 是通过 IDAL 来调用 DAL 的。但实际是即使你如此编码:“ IUserDAL iUserDal = ClassFacotry.CreateUserDAL() ;”,那么在执行“ iUserDal.SelectUsers() ”时,其实还是执行的 UserDAL 实例,而不是 IUserDAL 实例,所以 IDAL 在三层中的位置是与 DAL 平级的关系。
    通过上面的介绍,基本上将三层架构的层次结构说明了。其实,本人有一个判断三层架构是否标准的方法,那就是将三层中的任意一层完全替换,都不会对其它两层造成影响,这样的构造基本就符合三层标准了(虽然实现起来比较难 ^_^ )。例如如果将项目从 B/S 改为 C/S (或相反),那么除了 UI 以外, BLL DAL 都不用改动;或者将 SQLServer 改为 Oracle ,只需替换 SQLServerDAL OracleDAL ,无需其它操作等等。本来想在文中加入一些具体的代码的,但感觉不是很必要,如果大家觉得需要的话,我再补充吧。
    总结:不要因为某个层对你来说没用,或者实现起来特别简单,就认为它没有必要,或者摒弃它,或者挪作它用。只要进行了分层,不管是几层,每一层都要有明确的目的和功能实现,而不要被实际过程所左右,造成同一类文件位于不同层的情况发生。也不要出现同一层实现了不同的功能的情况发生。

你可能感兴趣的:(实战剖析三层架构1)