文章写得比较浅显(主要是个人水平有限),大家可以读来消遣排砖。^^
第二篇 系统构架及分析
通过上一篇文章(http://yuandong.cnblogs.com/archive/2006/06/26/436395.html)的介绍,我们已经了解系统要实现的功能和大体方法,下面就让我们看一下系统的构架。图示如下:
图一:系统概要图
系统采用单服务器部署方案,在逻辑层次上划分为四个子系统,分别是用户界面(UI),搜索(Search),查询(Query),数据(Data)。图中箭头的方向表示依赖的方向,即数据子系统依赖于搜索和查询子系统,用户界面依赖于搜索、查询和数据子系统。其中数据子系统主要是通过实现搜索子系统的ISearchDataService和查询子系统的IQueryDataServicre两个接口来对整个系统提供服务。而UI作为整个系统的驱动方。
一下我们来具体看一下每一个子系统:
一、 Search子系统:负责访问Ftp服务器,给出服务器上的文件信息。
二、 Query子系统:定义了检索逻辑。
三、 Data子系统:主要是处理数据的储存和实现数据的检索。这个子系统直接和数据库及索引打交道。其中数据库类似于一个资源,保存从网上获取的原始数据,而索引则用于到数据的快速检索、排序、分页。设计中数据库采用MS SQLServer 2000。索引程序使用DotLucene开源项目。
四、 UI子系统:包括驱动整个系统的驱动程序、系统运行的监视器、日志、WebSite、WebService等。
然后我们再来看一下更详细的包设计图:
图二:系统包设计图
上图基本上是图一的细化。我们作一下分析:
1, Kernel包封装了系统对真实世界的映射,其主要内容包含FtpItem及其派生类FtpFile,FtpDir。还是用于表示服务器的Server类。所有的包都依赖于上述类。同时上述类是对真实世界的映射,是稳定的,不容易改变的,所以被依赖是正确的。
2, SearchBusiness包定义了搜索逻辑,主要包括IRobot,ISearchDataService等接口,以及FtpException及其派生类,各种事件等。显然这些类描述了系统用于搜索的业务逻辑。是系统搜索功能的核心。这个包不依赖于任何类,它规定了系统的行为,其他包依赖于此包,实现定义与此包得系统的行为。QueryBusiness包于此包的作用相同。
3, DataAccess包隐藏了所有的数据存储和检索的细节,对于外部程序而言,只通过ISearchDataService和IQueryDataServicre两个接口与该部分打交道,实现数据的存储和检索。同时该包使用了ADO.Net和DotLucene,用于具体的操作。
4, SearchFacade和QueryFacade对外部隐藏了搜索和检索的具体细节,给出了统一的访问接口(类似API)
5, 对于第三方组件EdtFtpNet的调用,采用了代理模式进行封装。类似的,属于UI的SearchApplication中,计划采用Log4Net作为日志,也应该用代理模式进行封装。
从以上的设计中我们可以总结一下几条:
1, 细节依赖逻辑、实现依赖抽象。业务逻辑才是我们系统真正的核心。系统的行为是关键。用《敏捷软件开发——原则、模式与实践》中的一句话说就是:“客户给我们钱,是要我们描述系统的行为。”
2, 依赖应该向稳定的方向进行。接口、抽象类、对现实世界的映射类,这些类是稳定的;业务逻辑是稳定的,依赖的方向应该向这些项目进行。
3, 尽量解耦合。比如接触数据子系统与业务逻辑的耦合、UI与具体的行为类的耦合等。从测试的角度来讲,我们完全可以在没有Data子系统的情况下测试Search和Query。仅仅构造一个实现接口的Mock类就可以了。
4, 对于第三方组件一定要封装。这是常识,一个是为了版权上的问题,另一个是为了解除系统对第三方组建的依赖,使对第三方组件的使用依赖于系统。
大体的构架就是这个样子了,但其实还很不完善。许多细节要到真正编码中才能发现。代码本身就是设计,对构架也有反作用力。构架也是在不断演化中的。
以后我会继续不断地将系统的实现过程写成文章,与大家共享。