- 基于widgets
所有表现逻辑(UI元素的渲染+状态存储)和领域业务逻辑,都混杂在一起,适用于小工具。简单直接。
- 基于MVC(Model-View-Delegate)
将表现逻辑和领域业务逻辑分开,View负责展示和交互,Model负责组织数据和执行业务。当需要聚焦到表单细节时,Model-View会通过Delegate交互同步。
- 基于MVVM (Model-View-ViewModel)
基于QML引擎+QML脚本构建前端View,ViewModel充当沟通Model和View的桥梁,并负责存储View的状态。
知识问答:
1️⃣ 我们知道,ui 元素通常具有严格的层级从属关系,使用mvvm架构时,需要在viewmodel 中设计严格的层级从属关系吗?
直接回答:绝对不需要,而且强行对应是 MVVM 的常见误用。
UI 的层级是视觉布局树(Panel 套 GroupBox 套 Button),而 ViewModel 的层级应该是业务数据聚合树(公司套部门套员工)。两者完全解耦,原因有三:
- 层级来源完全不同
· UI 层级:源于界面布局需求(为了对齐、分组、滚动)。
· ViewModel 层级:源于数据结构和业务逻辑(比如订单包含订单详情列表)。
如果 UI 里加了一个无数据的装饰性分组框(GroupBox),ViewModel 绝不能为此新建一个空对象层级。
- 跨层级暴露会破坏封装
ViewModel 的核心职责是暴露数据(Property)和命令(Command),而不是暴露"子控件"。正确的做法是:
· UI 通过 Binding 指向 ViewModel 的某个集合属性(如 ObservableCollection<ItemVM>)。
· UI 中的 ListBox 或 Repeater 负责为这个集合的每一项生成对应的视觉元素。
这种映射是"一对多"或"多对多"的,完全不需要 ViewModel 知道自己被放在了哪个 Grid 里。
- 适应 UI 重构
如果设计师决定把三个并列的输入框改成 TabControl 分页,UI 层级会发生剧变。但只要 ViewModel 暴露的属性不变(CustomerName、OrderList 依然存在),你只需修改 XAML/QML 界面,ViewModel 一行代码都不用改。如果强耦合,UI 重构就会导致业务代码重写,丢失了 MVVM 最大的优势。
那 ViewModel 完全没有层级吗?
不是。ViewModel 有自己的"组合"关系,但它是业务上的父子关系:
· 父 VM 拥有 子 VM 的集合(例如 MainVM 拥有 UserControlVM 实例)。
· 这层关系源于业务逻辑的"包含关系",而不是因为子 VM 在屏幕右上角。
结论:在 MVVM 中,UI 树是"容器树",ViewModel 树是"数据源树"。两者依靠 DataContext(数据上下文) 在运行时动态绑定,完全隔离。记住:不要让 ViewModel 知道自己在屏幕上的位置,它只知道自己要处理什么数据。
2️⃣在传统ui框架中,因为ui对象和领域业务强耦合,导致业务被分散在ui对象树的各个节点,看上去好像领域业务也有层级从属关系一般,是不是非常不合理?
回答: 你说的太精准了,一针见血。 这不仅"看上去"不合理,在软件工程上属于典型的 "逻辑伪造层级" 反模式。
为了帮你把这层窗户纸彻底捅破,我从三个维度拆解这种"不合理"的根源和危害:
- 为什么开发者会犯这个错?(根源)
传统框架(如 MFC、WinForms 或早期的 Qt Widgets)中,UI 对象是天然的"容器"。为了获取数据,开发者会顺着 UI 树向上找(例如 this->ParentForm->DataGrid->SelectedItem)。这种"就近原则"导致业务协调逻辑(如"保存按钮点击后刷新列表")被物理上写在了按钮事件里,而协调范围又恰好发生在窗口层级。久而久之,视觉的"包含关系"就腐蚀了业务的"调用关系"。
- 最大的痛点:UI 重构即业务重写
假设你的业务逻辑是"用户点击保存,验证数据,写入数据库,刷新表格"。
在传统耦合代码中,这个流程被拆解为:
· Button_OnClick 写验证。
· Button_OnClick 调用 DbHelper。
· Button_OnClick 调用 Grid_Refresh。
当设计师把"保存按钮"从窗口底部拖到工具栏下拉菜单里,你不仅要改 UI,还要把这段业务逻辑代码剪切粘贴到新的事件处理函数中。这种"物理挪动"极易引发变量作用域报错,并导致业务逻辑随 UI 树震荡。
- MVVM 如何用"扁平化"解决?
这就是 MVVM 的杀手锏:业务逻辑必须附着于数据模型(ViewModel),而非视觉元素(View)。
· ViewModel 是"扁平"的:它里面只有一个 SaveCommand 和一个 ObservableCollection<Item>。它不关心按钮在哪,只关注"保存"这个业务含义。
· UI 树只是"投影":无论按钮在窗口底部、工具栏还是右键菜单,它们都绑定(Binding)到同一个 SaveCommand。
此时,UI 树的层级变化完全不影响业务代码的执行流。你删掉工具栏里的按钮,业务逻辑还好好躺在 ViewModel 里,其他地方的绑定依然有效。
结论:
UI 树是"物件的摆放"(平面设计),业务逻辑树是"数据的流向"(程序逻辑)。强行把前者当成后者,就像用家具的摆放位置去定义一家公司的管理架构------沙发放在窗前,不代表财务部就要听窗台的指挥。MVVM 的本质就是切断这根错误的脐带,让布局回归美学,让逻辑回归领域。