我的想法
(“模型”)
有一个模型。只是数据没有方法(除非适合平台一些-simple-getters/setters)。
(“视图模型”)
在我看来,视图模型的基本原理是:
(1) 提供对 RAM 要求较低的字段备份副本,以便隐藏在其他视图后面的视图可以卸载和重新加载(以节省 RAM,直到它们从覆盖它们的视图后面重新出现)。显然,这是一个一般概念,可能对您的应用没有用处或不值得。
(2) 在具有更复杂数据模型的应用程序中,将所有应用程序字段布局在一个视图模型中比创建一个与每个可能的数据变化字段对应的简化模型的工作更少,并且更易于维护,并且通常不会显着降低性能。
如果这些都不适用,我认为使用视图模型是不合适的。
如果视图模型合适,则视图模型与视图之间存在一对一的关系。
可能需要注意/提醒/指出,对于许多 UI 工具包,如果完全相同的“字符串”对象被引用两次(在模型和视图模型中),那么字符串对象使用的内存可能很重要本身不是双重的,它只是多一点(足以存储对字符串的额外引用)。
(“视图”)
视图中唯一的代码应该是(必需的)显示/隐藏/重新排列/填充初始视图加载和(当用户滚动或单击显示/隐藏详细信息按钮等时)的控件显示/隐藏视图的一部分,并将任何更重要的事件传递给代码的“其余部分”。如果需要任何文本格式或绘图或类似内容,视图应该调用代码的“其余部分”来完成这项肮脏的工作。
(重新审视“视图模型”)
如果(...显示哪些视图的事实和...)视图字段的值是持久的,即在应用程序关闭/重新启动后仍然存在,则视图模型是模型的一部分 :--: 否则它不是。
(重新审视“观点”)
视图确保视图模型在适当的字段更改方面与视图同步,这可能非常同步(在文本字段中的每个字符更改时)或例如仅在初始表单填充时或者当用户点击某些“开始”按钮或请求关闭应用程序时。
(“休息”)
应用启动事件:从 SQL/network/files/whatever 填充模型。如果视图模型持久,则构造附加到视图模型的视图,否则创建初始视图模型并创建附加到它们的初始视图。
在用户事务或应用关闭事件后提交:将模型发送到 SQL/networkl/files/whatever。
允许用户(“有效地”)通过视图编辑视图模型(您是否应该在文本字段中字符的最微小变化时更新视图模型,或者仅在用户单击某些“开始”按钮时更新视图模型取决于在您正在编写的特定应用程序以及您正在使用的 UI 工具包中最简单的应用程序上)。
在某些应用程序事件中:事件处理程序查看视图模型中的数据(来自用户的新数据),根据需要更新模型,根据需要创建/删除视图和视图模型,将模型/视图模型刷新为需要(以节省 RAM)。
当必须显示新视图时:在创建视图模型后立即从模型中填充每个视图模型。然后创建附加到视图模型的视图。
(相关问题:如果任何主要用于显示(非编辑)的数据集不应完全加载到 RAM 中怎么办?)
对于由于 RAM 使用考虑而不应完全保存在 RAM 中的对象集,请创建一个抽象接口来访问有关对象总数的信息,并一次访问一个对象。
接口及其“接口使用者”可能必须处理未知/估计和/或根据提供对象的 API 源而变化的对象数量。这个接口对于模型和视图模型可以是相同的。
(相关问题:如果任何主要用于编辑的数据集不应完全加载到 RAM 中怎么办?)
通过稍微不同的界面使用自定义分页系统。支持字段的修改位和对象的删除位 - 这些保留在对象中。将未使用的数据分页到磁盘。必要时使用加密。编辑完成后,对其进行迭代(一次加载页面 - 一页可以说 100 个对象)并写入所有数据或仅在事务或批处理中进行适当的更改。
(MVVM的概念意义?)
干净的平台无关方式允许和丢失视图中的数据更改,而不会破坏模型;并且只允许经过验证的数据进入模型,该模型仍然是数据的“主”净化版本。
理解为什么从视图模型到模型的流程取决于用户输入的数据验证,而从模型到视图模型的相反方向的流程不是。
分离是通过将了解所有这三个 (M/V/VM) 的代码放入一个核心对象中来实现的,该核心对象负责处理应用程序事件,包括高级别的启动和关闭。此代码必然引用单个字段和对象。如果不是这样,我认为无法轻松分离其他对象。
针对您最初的问题,这是一个关于模型中字段更新的验证规则相互关系程度的问题。
模型在它们可以存在的地方是扁平的,但引用子模型,直接用于一对一关系或通过数组或其他容器对象实现一对多关系。
如果验证规则的复杂性使得仅根据字段正则表达式和数字范围列表验证成功的用户表单填写或传入消息(并根据相关参考对象的缓存或专门获取的副本检查任何对象和/或键)足以保证对业务对象的更新将是“完整的”,并且规则由应用程序作为事件处理程序的一部分进行测试,然后模型可以只具有简单的 getter 和 setter。
应用程序可能(最好)直接在规则数量如此简单的事件处理程序中直接内联。
在某些情况下,甚至将这些简单的规则放在模型的设置器中可能会更好,但是这种验证开销会在数据库加载时产生,除非您有额外的函数来设置而不进行验证。因此,对于更简单的数据模型,我倾向于将验证保留在应用程序事件处理程序中,以避免编写这些额外的设置器。
但如果规则更复杂:
(a) 为每个复杂的模型更改编写一个采用特殊对象的单个方法,该对象实际上是包含无数字段更改数据的常用业务对象的组合,并且该方法可能成功或失败,具体取决于规则的验证- 立面图案;
或
(b) 首先创建模型或模型子集的“试运行”/假设/“试验”副本,一次设置一个属性,然后在副本上运行验证例程。如果验证成功,则将更改同化到主模型中,否则将丢弃数据并引发错误。
在我看来,在分析每个单独的事务时首选简单的 getter/setter 方法,除非您的应用程序的绝大多数更新都很复杂,在这种情况下,可以始终使用外观模式。
模型最终变得比具有(可能)简单 getter/setter 的一堆字段更复杂的另一种方式是,如果您开始“增强”类的 getter/setter(使用 O2R 映射器工具),或者添加额外的方面例如调用事务监控 API、安全 API(用于检查权限、用于日志记录等)、会计 API、预获取获取或设置所需的任何相关数据的方法,或获取或设置时的任何内容。有关该领域的说明,请参阅“面向方面的编程”。