界面逻辑和业务逻辑分离的重要性

我在最近的一个项目(WinForm)中遇到一个这样的问题,下面对问题陈述:
        某工资计算模块的界面很复杂,8个DataGrid分别和8个DataSet绑定,还有一大堆的TextBox关联另外两个DataSet里面的数据。更新界面的某一地方的数据,其他数据源相应的地方会变化。不谈论对需求分析到设计的好坏,在这样一个复杂的UI下面,处理数据同步问题令我好担忧。在最近的测试过程中,发生莫名奇妙的错误,找不到错误源,简直郁闷至死!主要是在某些情况下,数据变得不同步了,根本经不起“猴子测试”(在界面上乱点),悲哀至此,下定决心把关键部分重写。
        在重写过程中,我就发现了一个重要的问题:控制界面的逻辑和处理业务数据的逻辑应各自独立,就算界面显示数据有错误,但实际的数据仍是平衡的。
        举例:在DataGrid中,一个CellValue从10 -》100,差值(新值和旧值相减)是90。我们要根据这个差值去处理其他数据的同步。
        首先,问题是我们如何取出这个差值,开始我的做法是:DataGrid提供一个事件:ValidatingEditor。这个事件在输入的新值到写入数据源之前提供一个验证,在这里我们可以用EventArgs里面的新值和当前的值进行比较,得出差值。如果差值符合要求(业务逻辑),则把这个差值更新到各个相应数据源中去来保持数据同步。如果差值不符合要求,则提示错误信息,并还原原值。咋一看,什么问题也没有,逻辑也清晰,大家也觉得是吧?
        在测试过程中,问题就出现了,往往是输入一个新值后,“其他数据源”也同步了,但是回头一看,旧值还是旧值,新值并没有填充到“本数据源”中去,why?找了很长时间,虽然我们最终找出问题出在控件本身上面,但是如何从根本上杜绝这类问题的发生呢?
        就上面这个例子来说,我们找差值去同步数据的时候,在是写在ValidatingEditor这个事件上面的。如果在这个事件的处理过程中发生了一些我们异想不到的异常(可能是控件本身引发的或者是我们自己引发的),就会造成数据出错。所以进行了以下改造:
        考虑到如果ValidatingEditor验证成功,必然会引发一个CellValueChanged事件,这里可以肯定数据源是被改变的了。所以,在ValidatingEditor只负责数据验证和提示错误信息,验证不成功CellValueChanged不会被引发,如果成功,在事件CellValueChanged得到差值去同步各个数据源。注意:取差值时,尽量不要获取控件提供的值(上面是从EventArgs去取的),而直接数据源本身去取,这里就一定保证了数据的平衡性。我是这样得到差值的(DataSet某Row):

decimal v = (decimal)pdRow["PayMoney", DataRowVersion.Proposed] - (decimal)pdRow["PayMoney", DataRowVersion.Current];

这里就算控件本身发生问题而导致数据显示错误的话,但我们实际上的数据也是正确的(平衡)。只要在同步完毕之后,调用:

dataGridView.UpdateCurrentRow();

界面和数据源保持一致了。上面可能是特例,但是原则我认为应该这样做。希望对各位有启发。~ ^^
原文地址:https://www.cnblogs.com/wj/p/183367.html