系列一
—— 数据库常用模式
最近在研究架构的时候,一直有一个问题围绕着我,就是这些架构虽然好,但并不是有了好的架构软件开发质量就会提高,软件就会美观更贴近艺术。我感觉,要想开发出好的软件,架构、在架构之中层(我喜欢叫容器,我感觉先简单理解成package也可以)内部设计以及相关通用模块的积累都是软件开发重中之重,对于一个软件设计来讲,三个方面缺一不可,因为三个方面是相辅相成。我开的这个系列就是想简单说说我在相关设计上的一些思路,当然还希望高人路过时多多指点,让小弟多多学习,这里先谢过了。
我记得在前面的一篇文章中,我曾经写过,当时要给MVC中的M层设计一个架构。本篇文章主要是针对软件开发中的数据库层的设计进行的思考。文章在有些思想上和前面的文章有些许相同,不过更正和重新设计了一下新的思路,下面的说明中我将尽量使用UML图来进行说明,相信应该比看代码更清楚,而且写代码的话内容就太多了。
首先我明确一下自己的设计思路和设计目的:
一、希望上层直接使用对象数据。
二、下层和hibernate或jdbc能兼容。
首先我来秀一下主要思路的设计图:
上图中我们看到,整个软件项目是在一个com包中,里面主要是我们这次将的数据库层设计即DataBaseTier包。其结构已经一目了然了,我们以Hibernate为例,三个包的依赖关系为:EntityClass依赖EntityClassManagement,EntityClassManagement依赖HibernateManagement包。三个包我们都可以对该包进行“自测管理”,“信息监控”、“出入口统一化”等机制设置(“自测管理”,“信息监控”、“出入口统一化”等机制设置等都是软件设计的基本功,但不是本篇文章的重点)。这样做在QA上、入后维护上、代码美观方面都有良好的帮助。
我进一步说明,EntityClass包主要是放关系数据库中表的实体类,其内部结构如下:
整个包中有一个抽象的超类EntityClass,包的内部分为几个小包,分包是依据数据架构中主题域的设计而定的。多少个主题域为多少个包,每个主题域又都有一个超类SubjectEntityName继承EntityClass类,每个主题域中的每一个类对应着主题域中的一个实体对象。上述说的有一点点抽象,我给大家一个实现,看看就明白了。
上图显示的是一个主题域样例(图书馆管理系统的主题域片段),我们看到这个继承体系中,最后能被实例化的只有User,也就是说抽象类EntityClass和SubjectEntityName都是不能实例化的,我们可以藉由SubjectEntityName来确定实体对象的所在主题域。是不是很方便软件开发工程师理解其设计并进行开发呢。这个很明显使用了抽象工厂模式。
我们在回来看DataBaseTier这个图:
EntityClassManagement包中是Interfaces(接口)包和Implements(执行操作)包,这里主要是体现了(ISP)接口分离原则。最后是根据项目的需要所要使用的JDCBManagement包或者HibernateManagement包,我们以HibernateManagement包为例,其主要作用就是管理数据库的操作。
当然我上面讲了很多都是有一个前提条件的,就是数据都是来源我们自己的数据库,如果有其他系统的数据来源怎么办呢?我们看到,在设计中还有一个OtherSystemData包,执行数据操作的时候,这个包就起到了一个外系统数据交互的作用了。我在这部分的设计中使用比较多的模式是:(Factory)工厂模式、(Abstract
Factory)抽象工厂模式、(Adapter)适配器模式、(Composite)组合模式。
系列二——业务逻辑层常用模式汽车装配流水线
我们都知道MVC三层结构,其中的M(model)代表模型。模型封装了用户数据和处理数据的业务逻辑,体现了应用程序的当前状态,而且可以将用户数据状态的变化提供给多个显示该数据的视图共用。我看到了模型是多么的重要,那么模型是整个应用程序的核心,也是业务流程控制的要点。本次我主要就是围绕业务逻辑层设计来进行一些自己经验上的总结,希望高人留言指点。
业务逻辑层处在整个软件架构中处在一个承上启下的作用,上承控制层,下启数据层。前面我有一篇文章是专门说数据层的设计方法的,这里就接着上篇文章来说说重要的业务逻辑层。
设计目的为:
1尽量满足业务逻辑层承上启下的目的
2尽量使业务逻辑层设计学习起来简单
3尽量是业务逻辑层设计开发方便、快捷
我的设计思路主要来源于汽车装配流水线,大家都见过汽车装配流水线吧,一般“新闻联播”中要是有关系汽车方面的新闻时都会看过一点,如下图:
在这里声明一下,对于汽车生产我是外行,我这里主要是引用流水线的观念(对于汽车生产上面的具体细节要是说错了大家别介意),所有汽车从一开始上线到最后整车下线都是走一个流程,每个汽车的生产过程是一样的。那么这就引起我的思考,软件是不是也可以,我们在一个系统中设计不同的流水线,用户操作的本质就是和数据库或者硬件打交道,那么我们根据不同的流程也走向对应的流水线。
在这个思路下,我第一版的设计思路就出来了,如下图:
我将这个业务逻辑层分成了三个层次,他们是有关系的。基础平台是整个业务的基石,包含基础模块、安全、监控警告、错误处理和日志管理五个部分。
1基础模块包含整个系统相关功能的最低单元,比如:数据库操作、硬件操作、与外系统交互、一些公共组件呀等等。当然,这个基础模块的设计是有原则的,要遵循高内聚低耦合,要充分使用对象封装的特性。
2安全组件主要从四个角色去考虑整体的安全策略及具体的实施方案,这四个角色是:用户,应用,平台,服务。
3监控警告管理服务监控、系统监控、平台监控以及一些突发事件的警告。当然还会有相应的警告手段,比如呼叫中心、监控报错等等手段。
4错误处理主要是基础模块中报错的统一处理,根据不同的种类的报错,处理方式也不一样。
5日志管理主要包含基础平台内所以日志的统一管理,主要包含错误日志、监控日志、使用基础模块的一些痕迹记录日志、安全信息记录等等。
当然这些都是大区域上的分类,每个组件内部的设计也是必不可少的,我们要尽量使用设计模式和设计原则。
刚才说的底层基础平台主要是功能的最小单元模块,他的优点是我们根据功能进行分类,他们分布在基础平台的中间上。由于每一个都是功能的最小单元,他们的可服用水平就大大增加了,用汽车装配流水线来说就是基础平台上面的每一个模块就像是七成上的螺丝钉、钢板条、把手等最小化的汽车零件。
所用到的模式总结:
1在基础模块设计中主要遵循接口分离原则。
2监控警告管理、错误处理和日志处理都应使用工厂方法进行抽象。
3日志组件中每个日志实体本身应使用单例模式。
经过上面的努力我们已经有了基础平台了,我们回顾一下整体图:
用汽车来举例,现在我们开始搭建汽车的车门、车窗、座椅等大一点的零部件,这样位于第二层的基础服务平台就开始发挥功能。基础服务主要包含基础服务、基础服务流程化、基础模块集成三个部分。我们还拿汽车来举例,我们有了钢板、螺丝、把手,那么我们在基础服务流程化组件里面组件成车门。等于在整个汽车生产的大流水线中,车门生产的小流水线就是基础服务流程化。基础模块集成在大意上一样,但是概念上稍微不同,他将一些基础模块进一步进行抽象,升级到新的抽象高度,从而满足业务服务平台的需要。
基础服务又是什么呢?现在我来解释,我们在进行软件设计的时候都知道,面向对象设计六大原则,其中接口分离原则(ISP即Interface
Segregation Principle)。我们要将接口和实现分离的话,上层怎么看基础服务层提供的接口呢?就是这个基础服务中的基础服务组件,他里面是一系列接口的集合,根据上层业务的需要我们还可以调整接口的结构,方便业务服务层进行查找调用。
所用到的模式总结:
1服务流程化中的每一个对象其实都是使用了中介者模式,他们都是使用一系列基础模块。
2基础服务和服务流程化组件主要使用接口分离原则。
3基础模块集成组件主要是根据需要灵活使用组合模式、工厂模式。
经过上面的努力我们已经有了基础平台和基础服务平台了,我们再回顾一下整体图:
还剩下最上面,业务服务平台。业务服务平台的设计思路和基础服务平台在思路上基本一致,但是层面更高了,我们还拿生产汽车举例。现在我们有车门了、车窗等大零件了。那么我们可以开始组装汽车了。业务流程化组件和基础服务集成组件起到组装的作用。区别在于业务流程化组件所提供出来的服务已经是一个完整的业务流程了。基础服务集成组件是可以在一定程度上支持业务流程化组件,他们是个关联关系。比如:我们要制造一个双开门跑车和一个四门小轿车,其中对于车门这个部件,我们用工厂模式来搭建车门的话。则基础服务平台都能提供一个车门部件的服务,我们装车门就可以了。车灯、车顶之类的部件一次类推。我们的业务就由基础业务一点一点拼接而成了。
所用到的模式总结:
1业务流程化中的每一个对象也都是使用了中介者模式,他们都是使用一系列基础服务或者基础模块集成。
2业务服务和服务流程化组件主要使用接口分离原则。
3基础服务集成组件主要是根据需要灵活使用组合模式、工厂模式。
我在本片文章中将整个系统的业务逻辑层设计为三层,当然如果您开发的系统比较小的话,两层设计也是可以满足需要的。整个业务逻辑设计就是这样子了。这个设计根据项目的大小和具体业务的需要是可以自己变化的,希望大家多多提建议。
系列三——显示层之组合
现在的软件系统中,主要的开发形式是C/S和B/S两种。C/S又称Client/Server或客户/服务器模式。服务器通常采用高性能的PC、工作站或小型机,并采用大型数据库系统,如Oracle、Sybase、Informix或
SQL Server。客户端需要安装专用的客户端软件。B/S是Brower/Server的缩写,客户机上只要安装一个浏览器(Browser),如Netscape
Navigator或Internet Explorer,服务器安装Oracle、Sybase、Informix或
SQL Server等数据库。浏览器通过Web Server 同数据库进行数据交互。
根据上面的特征我们应该如何设计软件架构中显示层呢?既然客户端分两种,那么我的设计是不是也应该为两种呢?其实在我看来,无论是哪种客户端,本质无非都是将后台数据库中以及业务逻辑中相关的数据友好的显示出来,将用户看不懂的计算机数据转化成用户看得懂的用户数据。有了这个本质特点,我们的设计思路可以先根据显示层的特点进行通用设计,再给据两种客户端的特点分别进行实现。
主体思路是使用页面或者窗体组合的方式进行设计。我们在进行项目开发之前,每个页面或者窗体的界面原型,是显示层设计的一个关键,也是一个依据。拿B/S客户端来说,在开发之前,我们应根据页面设计的情况进行归纳和总结,在进行分类和设计工作。比如:在系统所有页面中,我们有多少不同的多级下拉框,多少不同的表格,多少不一样的菜单;当然也会有很对同等规格的自定义控件,比如一组按钮的菜单,节点树和列表的组合使用等。找到分析这些控件就由为重要,我以一组简单的设计为例,如下图:
这个设计主要是在Struts2.0框架下的显示层设计,WebPagesAction包主要是各个子系统的Action对象,这个分开主要是为了方便大型团队的并发开发。WebPages主要包含个子系统的页面以及一个自定义页面包,包里面所含所有开始应使用的自定义控件,目的是在并发开发页面的同时,最大限度的增加页面的可重用性。自定义控件包内部还应根据情况进行分类,为了便于大家理解,我拿个sina网页做个实例(这仅仅是我的想法,只是拿sina网页做个例子,我并不知道sina是否真这么设计的,这里特此声明一下)。
这个是sina的财经页面,看我画红框的地方,这两个地方都是标题菜单,不同点就在于数量、行数、背景等不同,但本质都是一组按钮组合而成的。为了表述方便我给他们起个名字,上面叫“主标题菜单”,下面的叫“分类菜单”。现在我们来进行设计,如下图:
RopicMenu和SortMenu是接口Menu实现的两种方式,EconomicsPage又聚合了这个接口,当然我们在这个页面里面看到多个这样的接口实现,从而完成这个菜单的设计。这里重点就是使用工厂模式和组合模式。
窗体和网页在设计的大体思路上是一样,只是名称不同而已。而且在一个项目中两种客户端都使用的情况也是有的,这个要根据项目实际的需要进行相关的改造,但是此设计思想可以不变。
这里我还要说明一下我个人对于两种客户端形式开发的拙见,我认为从软件开发角度而言,客户端的不同只是我们在进行数据显示时,显示的媒介不同罢了。而业务模型层中的数据层(持久层)和业务逻辑层的设计应该是和显示层分开的,所以说我们在进行设计的时候如论那种客户端,三层架构都是试用且好用的。只不过根据不同种类的客户端设计出来的结构会有所不同。比如,如果使用C/S客户端的话,就可以考虑一下尽量让一些不涉及数据的操作在客户端进行,从而减轻服务器端的压力。
|