Spiga

NGuestBook架构体系及实现指南

2009-02-25 00:01 by T2噬菌体, 4641 visits, 收藏, 编辑

      前几天我在我的Blog上发布了NGuestBook(点击这里下载),得到了很多反馈,在这里非常感谢大家的关注和支持。一些朋友在E-mail中提到,这个NGuestBook和我那个系列文章《基于.NET平台的分层架构实战》中讲的Demo有非常多不一样的地方,问我能不能单独写一篇文章说明一下这个新NGuestBook的架构方式和实现相关的问题。
      所以我专门写下这篇文章,对这个NGuestBook的架构体系和实现进行一个简要的说明,希望本文的内容能对大家有所帮助。
      有两点要特别说明:一是下面的内容中非正式的使用了UML包图,这里用UML只是为了描述一种架构,而不是建模,所以可能有很多不符合UML标准的地方,还请海涵了,只要您能看懂大体的结构表示就好。二是一下的描述,特别是图示,是以抽象架构工件为基本元素的,可能不会和源码中的工程、文件、类严格对应,但是,应该能很容易分辨出抽象工件元素和具体工程、文件等元素的对应关系。

总体架构

      我们先来看NGuestBook的总体架构图,如图1所示。


图1

      整体采用分层架构,这个思想很明显。从上到下依次为表示层(Web)、业务逻辑层(BusinessComponents)和数据访问层(DataComponents)。
      其中表示层直接依赖业务逻辑层,而业务逻辑层通过数据访问层接口依赖数据访问层。在业务逻辑层和数据访问层接口上,存在依赖注入组件(Factories),便于进行不同数据访问层的替换。
      这里预设了三个数据访问层,LinqDataComponents是使用linq to sql技术为ORM组件实现的数据访问层,SQLDataComponents使用传统的SQL语句访问数据库,这两个数据访问层都是以关系数据库作为数据源;XMLDataComponents是以XML文件为数据源的数据访问层,他们都是DataComponentInterfaces的实现。(特别说明:在提供的源代码中,只实现了LinqDataComponents,其他两个数据访问层只给出了扩展接口,没有具体实现。)
      Entities作为实体类组件,存放系统中用到的“贫血实体类”,这些实体类只用于存放数据,并负责在各层间数据的传递,是各层数据存取传递的媒介和标准。
      Utilities作为工具库组件,存放各种可复用的工具类。
      下面,对各个组件分别进行说明。

实体类组件

      实体类组件是现实世界业务实体在计算机世界中的表示,负责在各层之间的数据的传递,并维护数据格式标准。说通俗一点,就是各个层都“认识”这组标准实体类,传入、传出数据都以这种格式进行。
      为什么要这样呢?因为我们整体思想是尽可能保持各层间的耦合度较低,并相对独立,但是系统要工作,各层间就不可避免交换数据,因此,我们需要一种标准的、简单的、与各层无关的数据格式,否则如果强制某层强制其它层“认识”它特有的数据格式,就可能造成污染。
      例如,如果我们以DataTable为数据交换格式,那么业务逻辑层和表示层都得认识这种数据格式才行,如果有一天,我们要换数据访问层,不需要DataTable了,那么业务逻辑层和表示层都要修改。所以,我们要使用这种标准的、与特定层无关的数据格式作为交换格式,而如果某层有特定的数据格式,要在内部实现转换,对外传递的必须是这种标准格式。
      这里的实体类采用贫血实体类,而且由于业务很简单,整个系统只有一个实体类:MessageInfo。


图2

工具类组件

      工具类组件里是一些可复用的工具性类,这里主要包括三个:
      CacheAccessor:用于缓存的存取操作。
      SessionAccessor:用于Session的存取操作。
      ValidateHelper:用于数据验证的相关操作,主要用在表示层里。


图3

数据访问层接口

      数据访问层接口规定了数据访问层应该实现的方法,并作为业务逻辑层的依赖接口。
      由于整体只有一个实体——Message需要数据持久化,所以数据访问层接口只有一个接口文件。


图4

基于linq to sql的数据访问层

      NGuestBook实现的数据访问层是基于linq to sql的。总体来说,开发小型项目时,linq to sql是不错的ORM解决方案。数据访问层的内部架构如图5所示。


图5

      其中DataClasses是linq to sql框架根据数据库自动生成的特有实体类,用于linq to sql的操作。而数据访问主部件MessageDataComponent仅仅依赖DataClasses,这是因为MessageDataComponent的linq to sql操作必须使用这种特殊的实体类。
      而对外交流时,又需要使用公共实体类MessageInfo,所以,我们需要一个EntityConvertor,作为两种实体类之间的转换器,这个转换器是这个Linq to sql数据访问层的内部机制,对外部一律透明。
      这里要注意,EntityConvertor是一个概念上的工件,实际实现时其功能集成于MessageDataComponent。

业务逻辑层

      业务逻辑层实现主要的业务。这里的业务逻辑层有两个工件:AdminBusinessComponent和MessageBusinessComponent。其中后一个主要实现各种留言的业务操作,而前一个是管理员的业务操作。由于管理员的信息是记录在配置文件中而非持久化在数据库中,所以这个业务工件并不需要数据访问层的支持。
      这里特别提醒,朋友们可以仔细看一下业务逻辑层的方法命名和代码,就会明白,即使在如此微小的系统中,业务逻辑层也不是对数据访问层简单的封装调用,业务逻辑和数据访问是完全两个不同的概念。


图6

依赖注入组件

      依赖注入实现了依赖配置动态选择数据访问层并注入业务逻辑层中,实现两层之间的解耦,具体实现的基础是Abstract Factory模式,并配合了反射机制和缓存机制。


图7

      如图7所示,依赖注入组件的主要工件是DataComponentFactory,它是一个反射工厂,它可以通过反射机制加载某个指定的数据访问层,而后将其注入到业务逻辑层中。至于具体加载哪一个,则依赖Web.config中的配置。
      两外,它还依赖CacheAccessor实现缓存机制,对加载过的数据访问组件进行缓存,提高系统运行效率。

表示层

     NGuestBook的表示层使用了Microsoft ASP.NET MVC框架,版本是Releasse Candidate,所以,整个表示层的架构符合MVC模式。


图8

      由于ASP.NET MVC的架构原理非常复杂,这里就不将具体细节全部表述。大体架构如图8所示,Controllers控制器组件是整个MVC的核心,负责整体的调控。而Views视图组件则使用aspx页面实现,Filters是一些拦截器类,主要实现了身份验证和异常处理的功能。而Controllers直接依赖BusinessComponent完成业务功能,所以BusinessComponent实际上可以看成是MVC的Model。
      实际上,表示层还依赖工具类组件完成Session存取和数据验证的工作。

总结

      以上就是NGuestBook架构的一个简单说明,限于篇幅,不能完全顾及到每一个细节,还请见谅。希望以上内容对大家有所帮助。
      NGuestBook可以这里下载:

Creative Commons License

本文基于署名-非商业性使用 3.0许可协议发布,欢迎转载,演绎,但是必须保留本文的署名张洋(包含链接),且不得用于商业目的。如您有任何疑问或者授权方面的协商,请与我联系

Add your comment

20 条回复

  1. #1楼 Ryan Gene      2009-02-25 00:20
    貌似和我现在做的一个小框架架构差不多,区别在于我数据层用了NHibernate,另外还是3层Web, BLL, DAL,只是把DAL抽象了一下,变成IDAL,BLL面对的是IDAL,另外用domain object作为三层的数据契约。

    刚开始做不久,等有些成果以后和楼主交流 :)
     回复 引用 查看   
  2. #2楼 灵动生活      2009-02-25 01:08
    架构比较通用 和我目前的架构很像
     回复 引用 查看   
  3. #3楼 沉默是金      2009-02-25 08:12
    谢谢楼主分享!!博园需要你这样的人!!!
     回复 引用 查看   
  4. #4楼 艾新      2009-02-25 08:51
    谢谢楼主分享!不错,不错!能不能把你的源代码发一份到我的邮箱:fjmazhicheng5522@163.com。我这里网速很差,下载不了,谢谢了!
     回复 引用 查看   
  5. #5楼 毁于随      2009-02-25 09:11
    喜欢PD画的UML,简洁明了.
     回复 引用 查看   
  6. #6楼 张明海      2009-02-25 09:58
    如何能象校内那样处理海量数据呢?比如现在有100000人同事使用该留言本,谢谢!!!!
     回复 引用 查看   
  7. #7楼 GUO Xingwang      2009-02-25 10:39
    楼主写的文章很实用,而且简单明了,很推荐!
     回复 引用 查看   
  8. #8楼[楼主] T2噬菌体      2009-02-25 10:42
    @艾新
    已发送到你的邮箱
     回复 引用 查看   
  9. #9楼[楼主] T2噬菌体      2009-02-25 10:46
    @张明海
    我对海量数据处理没有经验。
    但是根据一些以前看过的东西,处理海量数据关键在于两点:一是分布式架构,二是负载均衡。
    因为我不是很懂这些,就不多说了。你可以请教一些这方面的高手或查相关资料。
     回复 引用 查看   
  10. #10楼 杨荣平[未注册用户]2009-02-25 10:51
    邮件已经收到,特来感谢!!
     回复 引用   
  11. #11楼 小No      2009-02-25 11:40
    个人觉得你的DataComponentFactory组件实现方式不太好,不够灵活,应该再改进一下

    因为:

    1. 其实你把所有DataComponent的命名空间都已经在web.config里写死了。
    假如我的LinqDataComponent项目下还有其他的文件夹,这时命名空间就不是
    NGuestBook.LinqDataComponent,这时我就必须手动修改命名空间

    2. 你把所有DataComponent的类名也规定死了,也就是说无论什么DataComponent它的类名都必须是一样的。

    我觉得你应该参考一下.NET Provider或者UNITY的实现方式
     回复 引用 查看   
  12. #12楼[楼主] T2噬菌体      2009-02-25 12:38
    @小No
    嗯,这是个问题。如果再灵活一点,可以使用Provider的方式。不过对于一般的项目,使用这种反射方式实现依赖注入,基本够用。如果项目可能会有命名空间的变更和类名的变更,则这种方式就不适用了。
     回复 引用 查看   
  13. #13楼 电脑智能2009-02-26 10:44
    555……估计楼主使用的是VS2008编译的,偶的2005打不开。

    不过细读了文章和代码,真是太感谢楼主,我是新手,虽然还有很多地方不懂。比如抽象工厂的那个模式。还有泛型的应用。不过绝对是一个好文章!
     回复 引用   
  14. #14楼[楼主] T2噬菌体      2009-02-26 17:55
    @电脑智能
    是VS2008环境下开发的,而且还得加装ASP.NET MVC RC扩展包才能打开
     回复 引用 查看   
  15. #15楼 愈圣      2009-06-18 10:54
    搂主文章很不错,也很实用。谢谢
     回复 引用 查看   
  16. #16楼 小驴      2010-02-26 10:46
    LZ,按你的要求修改app.config中的连接数据库字符串,但运行时提示连接不上!
    注:数据库、库表已经还原到我的数据库中,不过我用的是SQL2005的Express版本,不是是否跟此有关,望解答!多谢!
     回复 引用 查看   
  17. #17楼 小驴      2010-02-26 15:14
    呵呵,LZ我找到了,Properties中的Settings.settings文件也需要改连接字符串,好像只修改App中的且进行编译并不会自动修改Settings.settings中的连接字符串!
     回复 引用 查看   
  18. #18楼 乖乖小虎      2010-10-24 15:20
    每次想学习一些资料时,找到的总是楼主的。
    写的很好,非常感谢。
    牛人!
     回复 引用 查看   
  19. #19楼 天羽      2010-12-01 10:51
    无法下载代码.
    hdlrich1005@163.com
    如果可以的话,麻烦发一份代码给我学习下,谢谢.
     回复 引用 查看   
  20. #20楼 龙仪      2011-03-20 07:46
    请楼主发我一份,谢谢
    gl_job@163.com
     回复 引用 查看   
发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1397505 D/rWNkhWUN8=