Vincent.Q

重剑无锋,大巧不工 电话:13867408830;QQ:154538878;邮箱:xiyang-0@163.com

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  60 随笔 :: 0 文章 :: 989 评论 :: 0 引用

 

已经很久没有写这个系列的了,距离上一篇好像快半年了。回首看看已前写的东西,真是有些幼稚,很高兴有人还会去看并评论,在此谢谢大家。前几天看了下金色海洋写的一篇文章,感觉一意犹未尽,自己也写了一篇,在此献丑了。

这篇文章相当于一个总结,也可以说是一种新的理解,我也在尝试。废话不多说,进入正题。首先还是要对一些名词解释下。

名词解释

数据域:无论是CS结构或BS结构的软件,页面都会用于展示和维护数据操作,比如:新增、修改、删除等。每个页面会有若干个数据模块,比如列表页面,一般只有一个grid网格控件,批量展示数据使用这就相当于一个数据域;也可能还有一个树控件,用于分组显示使用,这也可以看作一个数据域。还有单据页面,主明细表(2个数据域),主表+4个tab页(5个数据域)。

业务场景

一个页面/窗体,其实都是对数据进行操作,包括新增、删除、修改等。有的页面,可能新增操作就会有好几个,比如HIS软件中,检验模块列表,可能有检验新增和检查新增,如果把这两个操作比作两个类的话,那它们之间藕合的可能性很小,可能是两个密封类。但它们之间又有很多共性的东西,比如都是对数据进行新增等。如何将它们之间的共性和个性区分开来呢。这里我们就要引入第三个类了,这也是一般解藕的方法,把共性的东西放在第三个类里,然后共同引用。

数据域的作用就是把这些操作整合出来,封装成一个单独的类来管理这些。

数据域操作

下面是一个数据域所有完成的操作,可能概括不全。

l 主要操作

1. 加载数据并绑定到控件:获取dataset或datatable对象,绑定到grid等展示性控件。

2. 数据操作,执行新增、修改、删除等操作,还包括一些功能操作(根据名称获取其拼音输入码填充到拼音码栏目中)。在此期间,还进行简单的检测,例:必输字段是否为空等。这是界面层要处理的事情。

3. 数据操作完成以后,还需要填充一些UI层不需要填充,但又必须填充的栏目值,如:ID流水号、创建人、创建时间等

4. 数据保存检测,包括数据正确性检测(栏目值是否符合栏目类型)、数据准确性检测(栏目值符合自定义的规则,例:单据日期不允许超过本月底等)、数据重复性检测等;

数据删除检测,需要检验数据引用关系。

5. 业务检测,真正的行业业务检测,直接继承接口即可。这部分将是以后操作的重点,因为它涉及到一个行业的业务需求,不是一年两年就能搞清楚的。

6. 获取与保存时生成的同步sql语句。这句话有这样一个业务场景:主明细单据保存时,明细表数据可能先全部删除掉,再全部执行新增操作。这个操作就是获取delete from table_detail where danjuid = xxx这条sql语句。

7. 获取数据同步sql语法。这句话有这样一个业务场景:一个单据新增的时候,可能会同步触发另外一个模块的新增操作。这个操作就是获取该操作的sql语法

8. 获取该模块的sql语法,用于保存

9. 数据真正保存,批量执行sql语句,使用事务。

上述的操作过程,是数据从数据库里提取出来展示给用户,用户浏览并对数据操作,最后回填给数据库的过程。我的想法是,开发员只需要关注两部分内容即可:一部分是UI层的数据绑定Db字段值和保存前的数据收集。另一部分是行业业务层的操作。

程序分层

l 数据层

这个没什么好说的,就是封装了一些与Db操作有关的方法集,例:保存时使用事务之类的。

l UI控件层

这里我创建了三个项目,如图-1所示

clip_image001

图-1

其中,Navi.Kernel.UILayer项目是Webform和Winform控件所用到的通用方法,比如权限及各种控件参数的定义。

Navi.Kernel.UILayer.WebControls是Webform控件集,由于才开始接触,没封装很多。针对各种类型的方法,我们将它们分门别类的放在几个类文件里,然后由pageBase统一调用它们的接口,如图-2所示。

clip_image002

图-2

Navi.Kerncel.UILayer.WinConrols是Winform控件集,封装了一些常用的控件。

l Service

这层主要用来收集各种方法,比如:针对字符串、日期、文件、Db操作等,如图-3和图-4所示,创建了两个项目,分别用来加载接口和实体类。

clip_image003

图-3

clip_image004

图-4

使用这些方法的时候,我使用的是单例构造模式,如图-5所示

clip_image005

图-5

l Model

这个要详细说一下。在我的整个程序中,Model层是非常重要的一层,因为它贯穿整个程序,起着承上启下的作用。Model层包含两个子类,分别是Winform和Webform,分别对应CS和BS软件。

一方面它负责调用Db层、Service层的各个方法,相当于一个集合,如图-6和图-7所示

clip_image006

图-6

clip_image008

图-7

另一方面,UI层中会有很多模块,以His软件来说,会有检验单和检查单等。我会为它们分配一个Model文件,用于辅助UI层操作。

Model层中包括很多方法,上面描述的“数据域操作”的步骤中,加载数据、数据保存、数据删除等。如图-8所示

clip_image010

这是一个模块的列表页面,如果我们想要从Db中读取数据出来,并加载到指定的控件(不一定是Grid控件的)。首先我们创建一个类,继承自BaseModel类,如图-9所示

clip_image011

然后,我们只需在这个类的构造函数中配置若干信息即可,如图-10和11所示

clip_image013

图-10

clip_image014

图-11

在上面的图片中,AuthorID系列的属性是确定该模块的模块ID,整个系统中识别该模块的唯一变量,独一无二;ListEventLevel是定义列表页面工具栏按钮事件级别的,事件分为三个级别:祖先级别,所有模块均可以使用、模块级别,只被这个模块使用。自定义级别,即写在行业业务级别(可以针对不同的行业业务自行编码)。

ListMaster系列的属性,就是定义一个数据域所需要的各种参数,如:Sql语句、数据域所对应的Db表,数据存储位置(包括数据库和Xml文件),如果数据域有数据操作,还需要定义是否启用主键并设置如何获取主键。这里没有所谓的insert或update语句,是因为在提交数据库的时候,会根据行状态,自动生成insert或update语句,同时使用lognet生成日志,方便查看。图11的部分是设置附加属性,如grid控件的列标题等。

通过上述属性设置后,模块的非UI部分已基本完成,下面我们再看看UI层本身要做什么事情?如图-12所示

clip_image016

图-12

声明一个Mode层只属于该模块的文件。

首先加载页面标题,然后,加载工具栏数据(可以自行配置,也可以通过权限设置,确定按钮是否显示和可用,可精确到个人),最后,加载List.Master数据域数据,使用grid控件展示。

通过Model层的使用,UI层的压力减轻不少,只需调用Model层中已经配置好的属性即可,是不是很简单咯!我们再看看数据保存的部分,如图-13所示

clip_image017

图-13

它包含数据收集,数据验证和数据保存三个部分。UI层要做的事情就是收集数据,验证部分是通过配置文件完成,如:是否重复、数据准确等,当然,某些特殊的验证还是要自己写的,配置文件只负责常规的验证。如图-14所示

clip_image018

图-14

l Common层

这个层一般用来编写比较通用的功能,例:查找、高级检索、定位、统计等,如图-15所示。

clip_image019

图-15

以“查找”功能来说,也是创建一个类文件,继承自BaseModel类(因为它是Service的方法集合,相当于代理),在类文件中调用打开frmFind页面的方法,如图-16所示

clip_image020

图-16

我们在业务模块使用“查找”功能的时候,只需要这样编写代码即可,如图-17所示

clip_image021

图-17

l Business层

这个层之所以放在最后说,是因为它即重要又不重要。说重要,是因为它是整个系统的血肉,如果没有它,整个框架就是一堆骨架,没有任何作用,是它来填充系统的业务功能;说不重要,是因为它只需要继承Service层中某些接口即可。如前面所说的,我们想重写新增操作,写在这里即可。如图-18所示,也是一个模块对应一个Business层文件

clip_image022

图-18

问题解答

l 有没有源码,希望提供一下

非常抱歉,由于某些原因,源码丢失。如果有什么不清楚的地方,可以随时留言。

posted on 2010-03-19 08:18 Vincent.Q 阅读(2166) 评论(11) 编辑 收藏

评论

#1楼 2010-03-19 08:25 阿水      
这句话有这样一个业务场景:主明细单据保存时,明细表数据可能先全部删除掉,再全部执行新增操作。这个操作就是获取delete from table_detail where danjuid = xxx这条sql语句。

很多人都这样实现数据的修改,但是如果在高并发的情况下会很麻烦的。当然如果业务逻辑就是要求这么做的,那是另外一回事。
 回复 引用 查看   

#2楼[楼主] 2010-03-19 08:28 Vincent.Q      
@阿水
嗯,是的,高并发的情况目前还不支持,因为没有详细研究.
 回复 引用 查看   

写得很认真,推荐+1
 回复 引用 查看   

#4楼 2010-03-19 09:07 Kain      
Model为什么要分Win和Web的?难道model要和特定的应用绑定么?这不太妥吧?
 回复 引用 查看   

#5楼[楼主] 2010-03-19 09:16 Vincent.Q      
@Kain
是的,毕竟Winform和WebForm还是有区别的
 回复 引用 查看   

#6楼 2010-03-19 09:49 吴峰      
记得有个数据库架构前辈说过,永远不要delete数据,删错的时候哭都来不及,特别是涉及到钱和利益的问题,确实没用的时候改状态..
 回复 引用 查看   

#7楼 2010-03-19 10:23 Brush      
一年前我研究出一套框架,名叫“动态信息管理平台”,框架已经架构好,只差写代码实施了。
 回复 引用 查看   

#8楼 2010-03-19 10:24 Brush      
回头等我弄上去后也写篇文章跟大家分享一下。
 回复 引用 查看   

#9楼 2010-03-19 14:03 道法自然      
我只是根据自己的理解提点意见:
1 命名不规范,从文中可以看出有类名为pageBase,有变量名为item_aaa和masterGrid,没有一个统一的格式,LZ可能才刚开始注意这个问题。
2 命名不妥当,像StringService没有给出意义、CheckService估计应该是BusinessRuleValidationService。
3 设计有点太规矩了,估计是借鉴了别人的架构,然后按照别人的规则做,因此给我感觉是做的还不够Smooth且有点过度设计。不够Smooth的原因在于从名字来看有点别扭。过度设计的原因在于看起来有点复杂,简单的设计能让人看一下名词就知道这一层是干什么的。
4 根据我的经验,我认为层次不宜太多。如果实在太复杂的话,可以横向+纵向进行分层,从而使每一个VS Project看起来都比较简单。我认为这是被很多书本给误导了。对于一个团队来将,“简单”很重要。

当然,以上意见并不是批评,估计你自己也觉得自己做的已经不错了,我和你想法一样。不过每个人都需要有所经历,经历不同,结论不一样。因此欢迎指正。
 回复 引用 查看   

#10楼[楼主] 2010-03-19 15:35 Vincent.Q      
@道法自然
嗯,不错,很客观,谢谢
 回复 引用 查看   

#11楼 2010-05-02 00:07 曾帆      
现在感觉数据还是作废比较好,尽量少删除数据。
对历史数据可以通过定期删除或者建一个历史数据表给转移到里面去。
 回复 引用 查看