随笔-77  评论-750  文章-51  trackbacks-22

一次进销存软件架构的实践(一)——概述

  很高兴又一次开始谈软件的架构了,不过这个的探讨与09年初写的浅谈MIS系统架构不一样,之前是理论,现在是实践,而且这次在实际项目中把之前的理论都实现了,有过之而无不及,验证和权限、各层之间的低耦合、不再需要托控件,等等都实现了,其实一切能够实现得益于这次架构的魂——一切数据都会经过架构的程序(我们有时叫底层,下面统一叫软件框架)。遗憾的是这次仍然是一个WinForm项目,如果是web开发那么其中的很多细节问题都需要从新思考,毕竟运行机制不同嘛。不过这个软件是一个非常成功的软件,而且实现了多语言、多单位和多币种等。

  上面所说的各层之间的耦合、不再需要托控件等(其实还有很多)这些挺表面的东西可能大家并不以为然,那从架构的角度来看下这个问题。

1.这是一个什么样的架构,为什么要这样架构 

  之前看到高焕堂大师的《Android应用框架原理与程序开发》这本书,书的第二章《應用框架魅力的泉源:反向溝通》,当我第一眼看到“反向沟通”这个词,我感到作者是我的知音,当然,当我看完这章后我就成了作者的知音,因为作者把什么是“反向沟通”和为什么要“反向沟通”这个原理表达的很精准。

  我常思考一个问题,那就是所谓的“三层架构”或者“多层架构”中如果实现表示层和业务层之间的低耦合,如果任由开发人员自己托控件,那么软件框架很难控制到它,虽然可以获得它,但在什么时候获得和这个控件是什么作用等都是软件框架无法决定的,无论是winform还是webform都是事件驱动式运行,开发人员会使用控件的那些事件和事件方法里写什么都是未知的,这样就可能会出现大量的代码冗余和层与层之间的高耦合,还有维护很不方便,同时这样也是一件浪费时间的工作。

  要想解决这些问题,那首先就得让软件框架去完成大部分工作,当然是与实际业务无关的工作。如果我们有一个保存按钮,我希望当点击这个保存按钮时软件框架自动调用业务对象中的保存方法,而不需要实际业务窗体去添加事件和写调用的方法,这就出现了两个问题,一个是软件框架如何知道当前需要调用哪个业务对象中的保存方法,这个很简单,只要业务对象都有一个基类,然后实现各接口(如:ISavable),软件框架自己去调用相应接口方法;还有一个问题是要保存的数据在哪里?看来软件框架需要保持有数据实体的引用才行。

  正如前面所说:一切数据(广义上的数据)都会经过软件框架。所以我的做法是:把需要用到对象都在软件框架的相应类里声明,像业务对象会在表示层的基类里声明,每一个窗体都有数据,这个数据也在表示层的基类里声明,等等(事实上在软件框架里声明的各属性很多,总共有十几个吧),开发人员需要给表示层基类的业务对象这个属性赋值,而数据则不需要去赋值,软件框架会自己去调用业务对象属性的查询数据的接口方法获得数据。

  这样一来软件框架中还剩一个问题就是窗体上的控件如何在软件框架中声明?因为只有软件框架保持对窗体上控件的引用才可以用统一的方法进行数据绑定、可见和可用权限、验证以及它们所需要的事件,这就需要软件框架自己去创建控件,至于实际业务窗体显示哪些控件是由实际业务窗体向软件框架定制的(这个定制比较复杂,我把这块单独抽出来作为一个业务外观层,通过它能定制控件以及控件行为,后面会详细说它)。

  可见:不再托控件不仅仅是目的还是实现这种架构思路的手段。

  正因为一切数据(广义上的数据)都会经过软件框架,软件框架才能控制一切,“反向沟通”才能好好的工作。


2.基本原理

  这里我将软件中会出现的窗体归了个类,每一种负责一种布局(窗体只负责布局,内部的控件等等由业务外观层去完成),比如带树的列表窗体(就是左边会显示一个树列表,右边一个Gridview的列表,树列表中的节点改变,Gridview列表的数据发生改变),这些窗体都继承自一个包含业务外观属性和一些方法的常用窗体类。实际业务窗体根据它的业务需要继承某一种布局的窗体,它还要使用业务外观层中的类创建窗体各个布局区域中的内容(很多控件),并给这些内容指定一个必选属性“字段名”(业务外观运行时会用这个“字段名”去绑定数据,并可以用这个“字段名”去索引到这个控件)和其他一些可选属性用来定制控件的内容、行为和样式等。

  这样一来,业务外观层是重中之重,它负责界面的绘制、绝大部分交互的调度以及几乎所有的非功能需求(比如:刷新后焦点行定位问题)。下面是个草图,业务外观层简单的画了下(因为下一篇会着重讲它),为了简单说明问题,也只放了一个用于业务的接口ISelectable,事实上是有很多的,比如保存等,业务外观层依赖于所有的这些接口以完成界面的操作,而开发人员在写实际业务窗体代码中不需要主动调用业务对象或者接口。

  如果换个角度去看,业务外观层不仅仅是上述作用,它是对平台(.NET)和组件的一层抽象,以另一种方式让开发人员编程,它还有它自己的运行机制。它还抛弃了以往拖拖拽拽操作麻烦、修改维护不方便(需要在设计器中设置,而现在可能只是移动上下行代码)、窗体风格不统一,同时它还屏蔽了第三方组件的使用(如果项目中用了第三方组件,但团队中不一定是每个人都很熟练的使用这套组件,那么这个方案能给大家节省很多时间)。


3.总结

  常用窗体为各种布局的窗体的基窗体,它声明了业务外观属性,子类可以访问业务外观属性并设置自己的外观。

  从常用窗体派生的窗体只负责布局,布局中的每一块称为区域,区域中的所有控件都是由业务外观层根据业务外观属性创建的。

  业务外观层根据实际窗体中定制的操作创建事件和绑定对应的事件方法完成与业务对象的交互。

  与业务对象的交互都是使用接口完成的,一个业务对象实现了某个接口就表示它拥有这样的能力,比如ISavable接口,就表示这个业务对象是可以保存的,所以我们定义了很多接口。

  下一篇讲解释业务外观层的设计和权限与验证的设计。

作者:Rick Carter
出处:http://pains.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

posted on 2010-07-23 08:57 Rick Carter 阅读(3250) 评论(24) 编辑 收藏

评论:
#1楼 2010-07-23 09:01 | 西就东城      
关注下,我thinking中
 回复 引用 查看   
#2楼 2010-07-23 09:09 | 西就东城      
你的保存接口定义,个人觉得粒度合适。不知道你定义多少个接口?可否公开
 回复 引用 查看   
#3楼 2010-07-23 09:19 |       
First and foremost,

希望当点击这个保存按钮时软件框架自动调用业务对象中的保存方法,而不需要实际业务窗体去添加事件和写调用的方法


这个观点在你做过超过5个以上的系统,并且是整体的去操作之后,会发现是错误并且幼稚D。。

时间能告诉你真相,不过代价在于你需要花多少时间才能体会到真相。

 回复 引用 查看   
#4楼[楼主] 2010-07-23 09:33 | Rick Carter      
@西就东城
可查询、可搜索、可保存、可分类、可提交、具有明细等接口

 回复 引用 查看   
#5楼[楼主] 2010-07-23 09:42 | Rick Carter      
@
1.对待业务问题,架构的本身就是对业务不可变的东西进行封装,所以我把那些几乎是每个窗体里面都用的东西封装了架构里;
2.我没有把所有的用户操作性的东西都写进架构,这也是做不到的,而且这个业务外观具有很好的扩展性,它不仅仅只能定制架构中已经定义好的功能,它也是可以由开发人员去执行自己写的代码的;
3.不太明白你说的话真正含义,特别是“整体的去操作之后”这个意思,你说的真相望赐教,谢谢。

 回复 引用 查看   
#6楼 2010-07-23 10:09 | 追萝驴      
引用辰:
First and foremost,

希望当点击这个保存按钮时软件框架自动调用业务对象中的保存方法,而不需要实际业务窗体去添加事件和写调用的方法


这个观点在你做过超过5个以上的系统,并且是整体的去操作之后,会发现是错误并且幼稚D。。

时间能告诉你真相,不过代价在于你需要花多少时间才能体会到真相。

时间会告诉你真相----当你做过超过10个以上的系统,就会发现,原来很多当初才做五个系统的时候得出的结论是错误并且幼稚D。。

 回复 引用 查看   
#7楼 2010-07-23 10:13 |       
@Rick Carter

1. 任何系统,业务本身是永远不可重用的。

这个观点要看你花多少时间去发现了。一旦你走上重用业务的道路,必定会不断对原本重用封装的业务模块进行扩张,最终导致配置复杂,代价和直接写业务一样。同时维护困难,让同行看不懂。

2. 操作本身也是永远不可重用的。

根据2个观点,不可重用的2个方面就让他们集合在一起。真正的框架是针对某个非业务的领域,例如数据安全、事务、权限。

 回复 引用 查看   
#8楼 2010-07-23 10:15 |       

你反驳我也大家没啥好驳的。因为你做过的东西我之前做过,最终自己推翻了自己。


 回复 引用 查看   
#9楼[楼主] 2010-07-23 10:15 | Rick Carter      
@
也许你们说的对,呵呵。
把不成功的系统都算上的话有7个。

 回复 引用 查看   
#10楼 2010-07-23 10:16 |       
@追萝驴

为啥年轻的小孩子们总是靠荷尔蒙冲动去办事。仅仅针对话去驳话。

也许这个是大多数荷尔蒙丰富的小孩们都会走的一条路吧

 回复 引用 查看   
#11楼[楼主] 2010-07-23 10:19 | Rick Carter      
@
对于你说的那两个观点,我想是在于重构的事,只要每次的变更都要重构下系统,考虑到扩展性等等。

 回复 引用 查看   
#12楼[楼主] 2010-07-23 10:33 | Rick Carter      
@
我没有反驳你,我很愿意接受所有的意见。
我更愿意说是靠激情办事,呵呵。

 回复 引用 查看   
#13楼 2010-07-23 10:47 | 追萝驴      
@辰
其实做过多少个系统不是关键,每个系统都有进步,都有自己的思考,这才是关键。当然,如果你一定要知道......我没有去认真数,20个左右吧。
年轻不年轻也不是关键,道理同上。当然,如果你一定要知道......哈哈,还是不说了,这是隐私。

我只说两点:
假如现在世界上没有ORM框架,那这个时候有人开发出了EF,你会不会否定这个东西,说他幼稚?要知道,ORM彻头彻尾就是在操作数据,里面也有Save之类的方法。

数据安全、事务、权限,这些东西,就和业务无关了吗?别的不说,权限在很多系统里是和业务密切相关的。按你的观点,这部分就丝毫没有抽象到框架的余地。

之前的回复当然有开玩笑的成分在内......不过,某种程度上它是真实的。一个当初你认为错误的设计,可能在一定时间之后,发现原来当初的设计方向并没有错,可能只需要做一些改动以容纳更多的变化就又可以变成一个好的设计。就拿这个例子,我妄自猜测一下,只需要ISavable接口的方法里包含一个Save(object ExtraInfo)方法就能容纳绝大多数的变化。----当然,我自己没有这么设计过,如果有考虑不周的,也请指出。

 回复 引用 查看   
#14楼 2010-07-23 10:47 | 阿水      
进销存!哈哈,我做了很多年!
有点经验,经销存系统框架主要解决两个问题
1)是业务层的可扩展性(方便扩展,不会把自己逼死。当然这个需要丰富的业务经验)。
2)UI层的快速开发,不要和我讲什么大道理,谁能又快又好的完成任务才是硬道理。
目前楼主的架构还没有看到对以上两点的阐述!

 回复 引用 查看   
#15楼[楼主] 2010-07-23 11:02 | Rick Carter      
@追萝驴
谢谢你回复这么多。
可能是我没说清楚,我表达能力不行,我已经把权限这块设计到软件框架里面了,开发人员不需要写大量的if,这块的设计我在http://www.cnblogs.com/pains/archive/2009/01/19/1378459.html 这个文章中有说,几乎是一样的。
没错,ISavable中有Save方法,呵呵,对于与业务的交互确实很难设计到通用的程度,所以像这个保存的方法我只是在软件框架里将数据做为参数传给它,实际怎么对待这个数据,就是开发人员自己的事了,他可以调用数据访问层将数据传给存储过程。

 回复 引用 查看   
#16楼[楼主] 2010-07-23 11:12 | Rick Carter      
@阿水
1.几乎没有对业务层进行过多的设计,开发人员可以自己写如何代码,只要必要的时候实现必要的接口即可。
2.当我把这个架构到可以使用时,我们项目组有人一天设计了将近10个窗体,并实现常用的操作,当然那时还没有设计好权限和验证这块,所以这些窗体上可以显示数据保存等等,如何快速,与之前这篇文章http://www.cnblogs.com/pains/archive/2009/01/19/1378459.html 的最后一段代码相似。

 回复 引用 查看   
#17楼 2010-07-23 11:37 | 追萝驴      
@Rick Carter
没什么,很高兴和你讨论,呵呵。

我只不过觉得,在讨论问题的时候,固然应当敢言,说错没关系,但至少应该有一个谦和的态度;不然,也不会跳出来,导致被指为毛头小伙。不过不论如何,听到有人说自己年轻,还是很开心的,哈。

 回复 引用 查看   
#18楼[楼主] 2010-07-23 12:00 | Rick Carter      
@追萝驴
谢谢,可能我的话造成误解了,我在此向大家道歉,我急于想知道同样的问题别人的做法,所以打出来的字不是心里的态度。从技术上我确实是毛头小伙,但真实年龄就不是了,我真希望自己年轻,呵呵。

 回复 引用 查看   
#19楼 2010-07-23 12:56 | 滔滔踏浪      
无代码,无真相
 回复 引用 查看   
#20楼 2010-07-23 13:00 | 吉桂昕      
引用滔滔踏浪:无代码,无真相

非常赞同

 回复 引用 查看   
#21楼 2010-07-23 13:26 | 小军人      
业务很难重用。
 回复 引用 查看   
#22楼[楼主] 2010-07-23 14:32 | Rick Carter      
@吉桂昕
@滔滔踏浪
后面篇幅会放些关键的伪代码,不过还是会以UML为主。

 回复 引用 查看   
#23楼 2010-07-23 18:20 | 追萝驴      
@Rick Carter
唉,老弟,我明显不在说你。

 回复 引用 查看   
#24楼[楼主] 2010-07-23 19:12 | Rick Carter      
@追萝驴
哦,我理解错了,对不住,谢谢。

 回复 引用 查看   
发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1783411 Av2yOQ1UAfQ=