代码改变世界

浅尝三层架构

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界面的窗体或者WebFormaspx是最上一层,它们对应的代码后置(codebehind)文件Form.csaspx.cs是第二层,然后再有一个访问数据库的代码,比如ado.csSqlHelper.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),

    //所以造成业务层无事可做,

        //只起到了一个转发的作用。但这不代表业务层可有可无,

    //随着项目的增大,或者业务关系比较多,

        //业务层就会体现出它的作用来了。

        //此处最可能造成错误的,就是把数据操作代码划在了业务逻辑层,

    //而把数据库作为了数据访问层。

        //例如:SelectUserUserInfo userInfo);IsExistUserInfo 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以外,BLLDAL都不用改动;或者将SQLServer改为Oracle,只需替换SQLServerDALOracleDAL,无需其它操作等等。

 

具体的区分方法:

n         数据数据访问层:主要看你的数据层里面有没有包含逻辑处理,实际上他的各个函数主要完成各个对数据文件的操作。而不必管其他操作。

n       业务逻辑层:主要负责对数据层的操作。也就是说把一些数据层的操作进行组合。

n       表示层:主要对用户的请求接受,以及数据的返回,为客户端提供应用程序的访问。

n        

为什么要分三层:

       我们用三层结构主要是使项目结构更清楚,分工更明确,有利于后期的维护和升级。它未必会提升性能,因为当子程序模块未执行结束时,主程序模块只能处于等待状态。这说明将应用程序划分层次,会带来其执行速度上的一些损失。但从团队开发效率角度上来讲却可以感受到大不相同的效果。

n         不分层也就是说所有实现都在页面代码内实现,这样的程序将导致单个文件或单个类的代码量极大,出现BUG你最好的方式就是设置断点并跟踪。而且工作人员离职,下一个接班人也比较头大。

n       分层后整个结构十分清晰,出现错误后你马上就能反映到这是哪里出的问题。而且,随着经验的增加,一个成熟的框架能够帮你解决更多的问题。

 

分层的优点:

n         开发人员可以只关注整个结构中的其中某一层;

n       可以很容易的用新的实现来替换原有层次的实现;

n       可以降低层与层之间的依赖;

n       有利于标准化;

n       利于各层逻辑的复用。

分层的缺点:

n         降低了系统的性能。这是不言而喻的。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成。

n       有时会导致级联的修改。这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码。

 

总结:

不要因为某个层对你来说没用,或者实现起来特别简单,就认为它没有必要,或者摒弃它,或者挪作它用。只要进行了分层,不管是几层,每一层都要有明确的目的和功能实现,而不要被实际过程所左右,造成同一类文件位于不同层的情况发生。也不要出现同一层实现了不同的功能的情况发生。

说明:

  本文主要参考园子里的大侠们的文章,有解释不到位的地方还请指正。