CRM/ERP 企业管理软件中常见的七种程序设计模式
管理软件中的常见代码设计模式,来自于业务上的需要,有不恰当的地方欢迎批评指正。
1 RE-TRY 重试模式
场景:在连接数据库服务器时,如果SQL Server数据库没有启动或正在启动,我们需要有一个连接重试的策略。发送邮件通知时,我们也需要在发送失败后,多次的尝试发送以保证邮件能到达目的用户。
代码参考:
int maxRetry = 30;int retryInterval = 10000;for (int i = 1; i <= maxRetry; i++){try{//connect to the database server}catch (Exceptions exception){if (i < maxRetry)Thread.Sleep(retryInterval);elsereturn; //返回或停止重试操作}}
这种模式的主要是有一个重试行为,直到执行完成或是超过了约定的时间或次数则放弃。
2 Before-Perform-After 检查-执行-传送模式
场景:在做一项业务操作前,子类为了重写(override)基类的行为必须先做条件或环境检查,然后执行相应的业务操作,之后还可以将此次操作的结果继续传送到其它业务单元中。
以打印报表为例子,业务窗体需要先检查当前登录用户是否具备打印权限,如无权限则取消本次操作。代码例子:
protected internal virtual bool DoPerformPrint(){CancelableRecordPrintEventArgs e = new CancelableRecordPrintEventArgs(this.CurrentEntity, selectionForumlas, formulaFields, parameterFields);this.OnBeforePrint(e);if (this._beforePrint != null)this._beforePrint(this, e);if (e.Cancel)return false;this.Print(ref selectionForumlas, ref formulaFields, ref parameterFields);EventArgs args = new EventArgs();this.OnAfterPrint(args);if (this._afterPrint != null)this._afterPrint(this, args);}
通过这段代码应该容易理解我说的这种设计模式,第一段是条件检查,如果我们在子类中传入参数e.Cancel=true,则
此方法返回,不再执行Print方法。这种设计模式在事件机制中用的比较多。基类为了控制好业务单元整体的行为,同时又不失去灵活性,可以参照这种模式。
3 TRY 尝试模式
场景:尝试性的去执行某一个业务单元,并以它的结果来决定下一步的行为。
比如我们加载数据,如果加载失败了,则下一步要阻止数据绑定,再比如传送文件,如果双方连接失败,则要阻止文件传送。
代码例子:
private void LoadData(){try{FindAndLoadData ()this._isDataLoaded = true;}catch (Exception exception){this._isDataLoaded =false;}}
这个模式的关键就在于定义的变量_isDataLoaded。在这个方法中,我们尝试去加载数据,如果有异常,则将此变量设为false表示加载失败,其它的业务单元检查到此变量的值以决定下一步操作。
这种行为也有危害,它隐藏了真实的异常原因,常常用在一些界面操作中,频繁的抛出各种异常会让用户反感,这时可以参考这种模式,尝试操作失败后,根据状态值阻止错误进一步发生。
4 BackgroundWorker 多线程工作
场景:在一些业务计算或是读取数据等耗费时间的业务操作,比如物需求计算,工作单批次发套料,计划订单发放等业务中,耗费的时间相当多,这种模式可改善效率。
应用代码例子:
List<LoadMasterScheduleWorker> workers = new List<LoadMasterScheduleWorker>();for (int i = 0; i < MAX_RUNNING_THREAD; i++){LoadMasterScheduleWorker worker = new LoadMasterScheduleWorker(this, mrp, mpsRows, loadedMpsItems);workers.Add(worker);}WorkerThreadBase.StartAndWaitAll(workers.ToArray());MAX_RUNNING_THREAD通常取当前系统的CPU个数(MAX_RUNNING_THREAD),在实际工作的线程中,采用下面的方法执行数据分配并启动相应的业务操作:
while (_mpsRows.Count > 0){DataRow mpsRow = null;if (!_mpsRows.TryTake(out mpsRow))break;LoadMasterSchedule(_mrp, mpsRow);}
从Dictionary<DataRow>集合中不停的TryTake数据行(DataRow)来操作,直到取完所有的数据为止。
需要注意前一段方法的最后一句StartAndWaitAll方法,这里要等待当前所有子线程执行完成,避免数据没有操作完就进行后面的业务操作。
WorkerThreadBase的源代码参考这里。
http://stackoverflow.com/questions/597590/c-sharp-threading-patterns-is-this-a-good-idea
http://files.cnblogs.com/files/JamesLi2015/WorkerThreadBase.zip
5 Data Class 数据类
场景:减少代码中不必要的字符书写错误,改善程序可维护性。
旧代码是这样的:
DataTable query = new FastSerializableDataTable("BomRoutingTable");query.Columns.Add("BomNo", typeof(string));query.Columns.Add("SeqNo", typeof(decimal));query.Columns.Add("OpCode", typeof(string));
应用数据类之后,代码是这样的:
DataTable query = new FastSerializableDataTable("BomRoutingTable");query.Columns.Add(BomFields.BomNo, typeof(string));query.Columns.Add(BomFields.SeqNo, typeof(decimal));query.Columns.Add(BomFields.OpCode, typeof(string));class BomFields{public const string BomNo ="BomNo";public const string SeqNo ="SeqNo";public const string OpCode ="OpCode";}
新代码设计方式增加了一个类型定义,增加了一点复杂性,同时改善可维护性。创建DataTable的列来自于一个类型定义,如果有多个创建表的地方,则可显著改善书写效率。
6 History 历史记录
场景:ERP中标准物料清单需要通过ECN来变更,若是将此模式应用到其它业务,则做采购单修改或销售单修改等其它单据,也需要记录变更前的资料。
例子代码:
BomHistoryEntity bomHistory = new BomHistoryEntity();InitialBomHistoryHeaderInActivation(bomHistory, ecn, canUpdate);return bomHistory;
变更记录相当于流水帐,记录每次业务修改前的值。变更记录还可以通过数据审计功能来实现,不过审计功能过于抽象,只能记录到表的字段变化,要实现两行数据记录字段值的精确比较,还需要开发接口程序以适应特定的业务单据。
历史记录模式最大的杀手就是反审核,反过帐,若业务单据可以反复修改,审核之后退回,反审核又可以修改,这样反复的操作,会产生大量的历史数据。
7 Hash Verify 哈希值验证
场景:文件传送时,在文件传送完成后,需要验证文件传送前后的MD5值或SHA1是否一致以保证文件没有丢失字节。
在一些重要的业务场景,比如转帐,充值,系统登录,在业务操作完成后我们还需要验证一下业务发生是否合理。
代码例子:
session = Login(userId, passwordHash, companyCode, languageCode, hostEntry.HostName, domainUserName, currentProcess.SessionId)string clientHash = Shared.GetMD5HashValue(string.Concat(new object[] {AssemblyVersion.Company, AssemblyVersion.Product, AssemblyVersion.Version, AssemblyVersion.FileVersion, AssemblyVersion.Product, session.UserId, session.UserGroup, session.CompanyCode, session.SessionId, session.LanguageCode, session.HostName, session.DomainUserName}));string privateKey = "...";string serverHash = RSACryptionHelper.DecryptString(session.ClientHashValue, privateKey);if (string.CompareOrdinal(clientHash, serverHash) != 0)throw new AppException("Unable to login, unexpected error detected");
第一行代码登录成功之后,服务器返回一个session会话对象,此对象包含一个ClientHashValue的MD5值,与此同时我们将客户端的登入信息,再次构造成一个字符串进行MD5处理,以比较两者的值是否一致,若不一致可能是非法登录请求,抛出异常,阻止登入系统。
这个方法也可应用于多版本策略中,系统要阻止3.2版本的客户端登录到2.1版本的服务器端,注意到上面的代码中有Version参数,会抛出异常。这样可保证一台电脑安装多个版本的服务器端而不相互冲突。
CRM/ERP 企业管理软件中常见的七种程序设计模式的更多相关文章
- 常见的七种Hadoop和Spark项目案例
常见的七种Hadoop和Spark项目案例 有一句古老的格言是这样说的,如果你向某人提供你的全部支持和金融支持去做一些不同的和创新的事情,他们最终却会做别人正在做的事情.如比较火爆的Hadoop.Sp ...
- Java中常见的5种WEB服务器介绍
这篇文章主要介绍了Java中常见的5种WEB服务器介绍,它们分别是Tomcat.Resin.JBoss.WebSphere.WebLogic,需要的朋友可以参考下 Web服务器是运行及发布Web应用的 ...
- ORACLE中常见的几种锁
ORACLE中常见的几种锁: 0:none 1:null 空 2:Row-S 行共享(RS):共享表锁,sub share 3:Row-X 行独占(RX):用于行的修改,sub exclusive 4 ...
- Vue基础01vue的基本示例,vue的双向数据绑定,vue中常见的几种用法,vue相关常见指令
自学vue框架,每天记录重要的知识点,与大家分享!有不足之处,希望大家指正. 本篇将讲述:vue的基本示例,vue的双向数据绑定,vue中常见的几种用法,vue相关常见指令 前期学习基础,使用vue. ...
- JS中常见的几种报错类型
1.SyntaxError(语法错误) 解析代码时发生的语法错误 var 1a; //Uncaught SyntaxError: Invalid or unexpected token 变量名错误 c ...
- PHP中常见的五种设计模式
设计模式只是为 Java架构师准备的 — 至少您可能一直这样认为.实际上,设计模式对于每个人都非常有用.如果这些工具不是 “架构太空人” 的专利,那么它们又是什么?为什么说它们在 PHP 应用程序中非 ...
- css中常用的七种三栏布局技巧总结
三栏布局,顾名思义就是两边固定,中间自适应.三栏布局在开发十分常见,那么什么是三栏布局?例如当当网首页边商品导航和右边导航固定宽度,中间的主要内容随浏览器宽度自适应.效果如下图所示: 下面围绕的这样的 ...
- java中常见的几种Runtimeexception
转自http://blog.csdn.net/qq635785620/article/details/7781026 一般面试中java Exception(runtimeException )是必会 ...
- WCF中常见的几种Host,承载WCF服务的方法
1:写在前面 我们都知道WCF在运行的时候必须自己提供宿主来承载服务.WCF 本身没有附带宿主,而是提供了一个 ServiceHost 的类,该类允许您在自己的应用程序中host WCF 服务.然后调 ...
随机推荐
- css3之3D魔方动画(小白版)
在这里分享一下3D魔方动画,html5+CSS3即可完成~无图无真相,先上效果图 第一步非常简单,就是先将魔方的结构画出来.大家都玩过魔方,知道魔方是一个有六个面的正方体.这里我们先写一个大的di ...
- js 逻辑或
逻辑或操作符由两个竖线来表示||,属于短路操作符,也就是说,如果第一个操作数的求职结果为true,就不会对第二个操作数进行求值 var found = true; var result = found ...
- 常用.NET库使用总结
Json.NET 获取类实例对应的jtoken:JObject.FromObject() 获取数组实例对应的jtoken:JArray.FromObject() Json.NET将枚举转换为int R ...
- 【CQgame】[幸运方块 v1.1.2] [Lucky_Block v1.1.2]
搬家首发!!! 其实从初一我就写过一些小型战斗的游戏,但是画面都太粗糙,代码也比较乱,也就是和两三个同学瞎玩,但自从观摩了PoPoQQQ大神的游戏,顿时产生了重新写一部游戏的冲动,于是各种上网查找各种 ...
- android 从 phonegap 到 js webview 交互
像生活类.办公协同类. 动态添加,下载等. 1.phonegap 我这里用了旧的版本,可能新版本变化大了. 创建asset资源文件夹,然后新建index.html copy 相应的js 文件进来. 创 ...
- Linux内核补丁批量自动下载工具
Linux kernel官网cgit工具不支持按变更代码进行补丁搜索,想到个办法就是把补丁都抓下来,这样可以在本地搜索.花了2个小时写了个小工具,话不多说,直接看效果: E:\docs\TOOLS\p ...
- 利用CORS实现跨域请求(转载)
跨域请求一直是网页编程中的一个难题,在过去,绝大多数人都倾向于使用JSONP来解决这一问题.不过现在,我们可以考虑一下W3C中一项新的特性--CORS(Cross-Origin Resource Sh ...
- MVC4 项目迁移 服务器被配置为不列出此目录的内容
前言: 将服务器中已经发布在IIS7上的网站,迁移到虚拟机中. 方便以后出现问题了,可以在自己的虚拟机中做测试提高工作效率. 问题: 迁移的6个MVC项目中有俩个碰到如下问题. 应用程序"T ...
- Ubuntu环境变量(.profile)加载顺序
Ubuntu下启动的时候的的加载环境变量的过程大致为: /etc/enviroment /etc/profile -->/etc/bash.bashrc --> /etc/prof ...
- JQM开发Tips
1.radio Button 点击后有时候有高亮样式,有时候没有 解决方案: $("#task_form label").click(function () { $("# ...