




已阅读5页,还剩11页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
这里讲的是对MIS系统架构的一些局部位置的设计思路,也是我个人的想法,不敢以偏概全,不过包含了很多要素:权限、验证、流程、行为、结构、内容,还有表示层如何与业务层分离。 写在前面 这是对以前项目的总结,作为一个在别人架构的系统上写程序的开发人员,对系统架构提出新的想法我想这没什么可争议的。我经历了两个业务需求相似的项目,第一个项目我看不到架构的影子,看到不少用工具根据数据库生成的看起来很优秀的代码,花了几个月修改bug但最后项目还是黄了,这次的失败给每个人都上了堂课。但我到公司的时候负责架构的人和多个开发人员已经不在公司了,那时写代码的工作已经接近尾声,主要就是测试、改bug和报表,我是和剩下的人一起共事的。我到公司后就做报表,用DevExpress控件做报表,以致我对DevExpress的XtraReport报表很熟悉,之后在第二个项目中负责报表并写了关于XtraReport报表的一篇随笔 。做了一个多月的报表就去改bug了,改bug很容易,在我的印象中发给我的bug我都能改好并不会产生其他的bug,而且还对原有不合理的程序进行了优化,但遗憾的是在之后的几次演示中系统都没能完全的毫无错误的正确的走完。其中客户很挑剔,关于这个我是理解的,如果我们去买房子当然希望房子好的出乎我们的想像。项目无功收场,很多同事离去了,曾经大家起吃住欢笑的日子不在有了,特别是我们的经理,他离开让我很意外,当初就是他面试我进公司的,面试时只是让我做一个类似新闻发布系统,我甚至没有做出来,他看了下代码和我平时瞎捣鼓的东西,到会议室问我期望的待遇,约好时间我就来上班了。他走时我送了本书给他,现在元旦时他还会给大家发条祝福的短信。这次和剩下的几个人和另一组人进行了第二个项目,我从这边转到那边时架构已经做好了,当时我当心架构会跟前一个项目一样,到了之后看到比前一个大大的改进了。这个项目架构的很好,特别是界面层,界面进行了统一,或者说是标准化了下,一排按钮整齐紧挨着排列,每个按钮放在一个lebel上,设置这个lebel不可见后面的按钮会紧挨着跟上来,这点做的太棒了,它能给界面层设计带来很多启发,这点是我没想到的。这个架构将很多操作定义好,有时候像是定义死,不同的操作它会执行不同的代码并传不同的参数给一个虚方法,派生的窗体重写这写虚访法完成对业务层的访问(业务层往往是调用存储过程)。负责某个模块的开发人员要做的工作就是:写好各操作的存储过程;定义业务层对象;选择正确的窗体基类(主要有带树形的列表窗体、列表窗体和明细窗体)派生一个新的窗体,在这个窗体中使用业务层对象和一些公共对象做权限设置等初始化操作以及验证,复写虚访法,很多的地方都是用虚访法的,如验证,基类的事件中去调用这些虚访法,还有访问业务层对数据的操作也是在虚访法中去访问,基类会去调用这个虚访法。开发人员要写很多的if语句,并且大量的代码都在界面层去做,业务层显得及其单薄,当然架构人员当初肯定不是这样想的,实际工作中开发人员在没有指导和参考实例的情况下违背了架构人员的初衷。这个项目最后是成功的。学会总结,争取每次架构比前一个架构更进一步。 简单而繁琐的工作开发人员的痛 一个好的架构可以让开发人员有个赏心悦目的体验,他可以简单愉快的面对繁杂的业务问题,将精力放在困难但能给人带来挑战性和成就感的问题上,但往往不是这样。我们经常在初始化界面时要根据权限设置可见和可用,用了一堆的if语句,在业务层也要根据权限判断是否继续执行接下来的代码,同样验证也是有一堆if语句。每当写这样的程序时脑子里要想到有那些东西要设置权限,是可见还是可用,是那些关系表达式的组合,生怕漏掉或是写错任何一个。当发现错误时我们得看着长长而且相似的代码一时找不到错误的位置。虽然这些工作很简单,但很快会有人说:“嗯,这个地方需要改进。”给窗体设置内容时一个一个控件的选择,在属性中设置各个参数。特别是表格控件需要对每个列设置文本值各参数甚至还有事件,代码中可能还有权限。它需要一个一个的来,一会儿是复制张贴一会儿是鼠标选择焦点,切换来切换去会让思维停滞或转移,区区的零点几秒累计起来可是不小的数字。似乎我们的很多代码不是写出来的而是画出来的,除了直观没有其他的好处,这里不是否定可视化,可视化的操作也是产生代码的,只要把结构设置好,内容是可以根据业务层的数据自动完成的。还有操作,我们要添加很多事件去调用业务层的方法,如果业务层没有你要的方法就要去业务层加个,似乎界面层上的控制是事先知道业务层的的相应方法是做什么用的,耦合度问题? 问题分析和解决 对于MIS系统会遇到一下几个东西:结构、内容、权限、验证、流程、操作和数据。结构:好比框架,一块一块的区域。内容:结构中的内容,一般是控件。权限:我们总是用分支语句来做权限上的事,每个分支语句其实都可以看成一个关系表达式或关系表达式的组合。就像“12”或“(12|32这种形式)的真假值,用一个类来专门做这个是为了能够计算我们自定义的类型的关系,如图1。GetRestrict()方法计算并返回单个关系表达式的真或假。这里只写了5个静态关系操作符并且命名太过于直接了,实际开发时当然不能这样,大家能看懂就行。图12. 我们要得到的是一个关系表达式组合的真假值,这样我们会有很多的Restrict和一个表示它们组合关系的表达式,看图2。这里有一个实现了.NET类库IList接口的的Restricts类,它有一个属性RestrictExpression就是表示组合关系的,举例说明这个属性,(12|38)&9=9像这样的关系表达式的组合在这个属性里表示为”( 0 Restrict.| 1) Restrict.& 2”,相信大家已经明白它的含义了,中括号为Items数组中的一个。接下来的任务就是Parse()方法的事情了,由它去解析这样的表达式并返回布尔值,这个类中还要有验证RestrictExpression属性是否正确的代码,这些实现上的细节问题就不多说了。还要实现IList接口,这些方法在这个类图中就省去了,这样做是为了让它的调用着更方便操作它。图23. 一个操作就比如一个按钮,它有在它上显示的文本、它在什么情况下可见(Visible)和什么情况下可用(Enabled)、一个要执行的方法以及方法执行前的验证,似乎操作(行为)的类就这样定义:如图3.。这个比较头痛,行且这样。图34. 我们再来考察内容,就像一个控件,它有在它上面显示的文本、绑定到它的数据以及它在什么情况下可见(Visible)和什么情况下可用(Enabled),我们是不是漏了什么?对了,控件都有输入(如鼠标点击、键盘按下),这些输入会转化为事件,这就是我们的操作,因此每一个内容都有一系列的操作,我们的内容已经有个显示的文本属性操作类中的Text就省了,还有可见权限和可用权限也是。看看图4,在前面的图中已经画的类这里就不画了。其中Behavior类的属性Action是一个委托,接受来自领域对象的方法,如保存,委托DisplayRights接受来自Content类中的DisplayRights.Parse()方法,委托EnableRights同理,方法Operate()为传给界面层作为事件的方法,它先调用DisplayRights()和EnableRights()执行为真后,再调用OperateValidate.Parse()验证为真则执行Action()。可以看到事件方法的e参数的类型用了反射,根据Type的值获得类名字符串的。可以发现把所有的功能都集中到了Content类中,我想用它可以描述很多东西了,只要结构标准统一,一连串的Content对象就可以表示所要呈现的各种东西,就像Win32编程中的窗口的概念,打开的一个界面是窗口,一个控件也是窗口,完善Content类就可以等同于这样的窗口概念。图45. 我们会有个业务层的基类,它是抽象类,由它来统一访问数据访问层,如图5。图56. 接下来就是与我们要面对的问题有关的事情了,就是领域模型。由于我们面临的问题可能很复杂,这里无法做到概括所以的问题域,只是举个例子:单据,如图6。我们用一个抽象的基类Bill来定义共有的属性和方法,每个具体的单据继承它并加载数据、设置权限验证操作等等属性。当我们需要对数据库进行操作时(即序列化等问题)需要知道数据库或XML的设计,因此我们设计了类似ORM的框架,让它帮我们做对象关系映射和序列化的事,当修改了数据库,只要修改它就OK了,其中的接口不应仅仅这些,需要有更多的方法帮助我们知道对象关系映射的信息和对数据库的操作,同时要传IDa对象给它。注:我没有去了解过任何现有成熟的ORM框架,这里的设计思路与它们没有任何的关系,只是为了实现这样的架构而有了它,不能把它当成ORM框架来看,它应该有个基类以完成一些共有的属性和方法,这里没有仔细的去思考它。图6对于界面层的基类就是要设计好所需要的结构和根据业务层的对象添加相应的控件并设置属性和事件,如图7。对于结构,相应的基类画好就行。要显示什么内容就是遍历Bill类的MainContents : Content、DetailContents : Content和Behaviors : Content三个属性来设置相应控件,事件就是这三个中的Operations : Behavior属性,一个控件会有多个事件,根据Behavior类的Type : BehaviorType属性确定是那个事件,这在BehaviorType类中约定,将Behavior类的Operate方法赋给事件。因为不同的结构设置控件的属性不同,不同的窗体又有不同的结构,因此设置控件的属性的工作就放到了具体结构的窗体构造函数中(如FormDetail、FormList和FormTree),由具体的单据窗体的构造函数去调用。图7这样就很好的将业务层与界面层相分离了,界面层只负责将内容一种结构去显示,至于是显示什么内容是业务层的事,当我们要显示的某列的名字有改变时只是要去修改Content对象,将问题集中在一个对象里面。好了,整个结构的思路讲完了,大家可能已经看到大多数类的属性都是共有的,这里是为了表达自己的观点,是概念层的东西,并没有过多的去考虑实现上的细节,图8是张完整的类图。图8 被解救出来的开发人员 现在开发人员的工作就更加明确和清晰了,我们以订单这个东西来简单体验一下这个架构。首先我们定义一个实现IListable、ISavable和ISubmittable接口的类OrderPL,它要做数据库的表到DataSet数据类型(你也可以用你自定义的类型)的映射,订单拥有的操作保存和提交等等。然后根据需求我们会定义一个订单类,名字就是订单,主要内容可能是订单号、订货日期,明细内容是所订的货物,它有货物名称、数量、价格,订单有保存和提交两个操作,根据这些我们的Order类大致这样写(注意代码中的注释)。class Order : Bill private ILoadable _loadPl; private ISavable _savePl; private ISubmittable _submitPl; public Order() OrderPL pl = new OrderPL(); _loadPl = pl; _savePl = pl; _submitPl = pl; Data =_loadPl.Load(); Text = 订单; MainContents = new Content new Content( 订单号, DDH, /在任何情况下都显示 null, /流程 状态为0时可编辑 new Restricts(new Restrict new Restrict (Data.Table0.Row0ZT,0, Relative.= ) ,0), /没有针对该控件事件的操作 null ), new Content( 订货日期, DHRQ, null, new Restricts(new Restrict new Restrict (Data.Table0.Row0ZT,0, Relative.= ) ,0), null ) ; DetailContents = new Content /*货物名称、数量、价格*/; Behaviors = new Content new Content( 保存, , /保存只能是在状态为0、订单的所有者是当前登录用户并且当前登录用户有订单的保存操作权限下可用 /这里假定系统对订单的保存操作权限用0表示(每个操作都要有一个值来表示),同时这个值应该放到一个枚举中 /如果你还有其他的复杂的权限可以添加相应的类去做 new Restricts( new Restrict new Restrict (Data.Table0.Row0ZT,0, Relative.=), new Restrict (Data.Table0.Row0OWNER,User.ID, Relative.=), new Restrict (UserRights.GetRights(0),True, Relative.=) , 0&0&0 ), /同上 new Restricts( new Restrict new Restrict (Data.Table0.Row0ZT,0, Relative.=), new Restrict (Data.Table0.Row0OWNER,User.ID, Relative.=), new Restrict (UserRights.GetRights(0),True, Relative.=) , 0&0&0 ), /保存可拥有的多个操作 new Behavior /按钮被按下的操作 new Behavior( /表示是按钮点击操作 BehaviorType.ButtonClick, /验证,订单号不能为空 new Restricts(new Restrict new Restrict(Data.Table0.Row0DDH, Relative.!=) ,0), /保存数据的函数 _savePl.Save, new Restricts( new Restrict new Restrict (Data.Table0.Row0ZT,0, Relative.=), new Restrict (Data.Table0.Row0OWNER,User.ID, Relative.=), new Restrict (UserRights.GetRights(0),True, Relative.=) , 0&0&0 ).Parse(), new Restricts( new Restrict new Restrict (Data.Table0.Row0ZT,0, Relative.=), new Restrict (Data.Table0.Row0OWNER,User.ID, Relative.=), new Restrict (UserRights.GetRights(0),True, Relative.=) , 0&0&0 ).Parse() ) ), new Content( 提交, , new Restricts( new Restrict new Restrict (Data.Table0.Row0ZT,0, Relative.=), new Restrict (Data.Table0.Row0OWNER,User.ID, Relative.=), new Restrict (UserRights.GetRights(0),True, Relative.=) , 0&0&0 ), new Restricts( new Restrict new Restrict (Data.Table0.Row0ZT,0, Relative.=), new Restrict (Data.Table0.Row0OWNER,User.ID, Relative.=), new Restrict (UserRights.GetRights(0),True, Relative.=) , 0&0&0 ), new Behavior new Behavior( BehaviorType.ButtonClick, new Restricts(new Restrict new Restrict(Data.Table0.Row0DDH, Relative.!=) ,0), _submitPl.Submit, new Restricts( new Restrict new Restrict (Data.Table0.Row0ZT,0, Relative.=), new Restrict (Data.Table0.Row0OWNER,User.ID, Relative.=), new Restr
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年建筑工程中级职称考试《专业基础知识》试题库及答案
- (2025)劳动教育考试试题及答案
- 2025《体育与健康课程标准》试题及答案(两套)
- 摇一摇课件教学课件
- 江西省萍乡市2024-2025学年七年级下学期期末语文试题(解析版)
- 摄影技术基础知识培训课件
- 无菌技术试题及答案三基
- 2025水产购销合同模板
- 2025供需、协作合同范本
- 2025照明设备采购装饰合同协议书
- 【词汇】高中英语新教材词汇总表(共七册)
- 喷射混凝土工艺性试验总结
- 北京市各县区乡镇行政村村庄村名明细
- 笔迹、指纹鉴定申请书
- 古建亭子CAD施工图集
- 生产效率提升培训教材课件
- 【英语】人教版英语八年级英语下册阅读理解专题复习练习(含解析)
- 《植物生理学》课件第四章+植物的呼吸作用
- 2022版义务教育语文课程标准(2022版含新增和修订部分)
- 2022年出差管理制度员工出差管理制度
- 光学第一章-费马原理与变折射率光学
评论
0/150
提交评论