前几天我在我的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架构的一个简单说明,限于篇幅,不能完全顾及到每一个细节,还请见谅。希望以上内容对大家有所帮助。