Skip to content

Commit 71a08ab

Browse files
committed
mvvm model-view
1 parent 90cf8c4 commit 71a08ab

5 files changed

Lines changed: 294 additions & 3 deletions

File tree

src/.vuepress/sidebar.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ export default sidebar({
4848
"5 bridge_pattern.md",
4949
"6 factory_pattern.md",
5050
"7 chain_of_responsibility_pattern.md",
51+
"8 mvvm.md",
52+
"9 model_view_in_qt.md",
5153
],
5254
},
5355
{

src/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ editLink: false
2626
- [数组与链表](/algo/1%20array_and_list)
2727
- [队列与栈](/algo/2%20queue_and_stack)
2828
- [哈希表](/algo/3%20hash_map)
29+
- [二叉树](/algo/4%20tree)
2930

3031
### 架构设计
3132
- [设计原则](/design/1%20design_patterns)
@@ -34,6 +35,7 @@ editLink: false
3435
- [装饰器模式](/design/4%20decorator_pattern)
3536
- [桥接模式](/design/5%20bridge_pattern)
3637
- [工厂模式](/design/6%20factory_pattern)
38+
- [责任链模式](/design/7%20chain_of_responsibility_pattern)
3739

3840

3941
### 其他

src/design/8 mvvm.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
---
2+
title: MVVM 模式
3+
order: 2
4+
category:
5+
- 架构设计
6+
tag:
7+
- 设计模式
8+
- MVVM
9+
editLink: false
10+
---
11+
12+
MVVM(Model-View-ViewModel)是一种常用于前端开发中的架构模式,它将用户界面逻辑和业务逻辑进行分离,从而使代码更具可维护性和可测试性。MVVM 模式是由微软架构师 John Gossman 于 2005 年提出的,最初用于 WPF(Windows Presentation Foundation) 和 Silverlight 中,现已广泛应用于各种前端框架和工具,如 Vue.js、Angular、React+Redux 等。
13+
14+
### MVVM 的核心概念
15+
16+
MVVM 模式由三部分组成:
17+
1. **Model(模型)**
18+
2. **View(视图)**
19+
3. **ViewModel(视图模型)**
20+
21+
这三部分通过数据绑定(Data Binding)机制相互通信,实现界面和数据的自动同步。下面是各个部分的详细解释:
22+
23+
#### 1. Model(模型)
24+
Model 代表应用程序的数据和业务逻辑,通常是纯粹的 JavaScript 对象、类或者数据结构。它负责处理与业务逻辑相关的所有操作,如数据的获取、保存和更新等。
25+
26+
- **职责**
27+
- 管理应用程序的核心数据。
28+
- 处理业务逻辑,如增删改查等。
29+
- 与服务层(如 API)交互,获取或更新数据。
30+
31+
32+
#### 2. View(视图)
33+
View 是用户界面(UI)的展现层,负责将 ViewModel 中的数据展示给用户。它通常由 HTML、CSS 等构建而成,负责呈现数据和处理用户的输入(如按钮点击、表单提交等)。
34+
35+
- **职责**
36+
- 负责界面的展示。
37+
- 捕捉用户输入,并将其传递给 ViewModel。
38+
- 数据绑定机制确保视图能够实时反映 ViewModel 的变化。
39+
40+
41+
#### 3. ViewModel(视图模型)
42+
ViewModel 作为 View 和 Model 之间的桥梁,负责处理界面显示逻辑。它从 Model 中获取数据并提供给 View,还处理用户的输入,并将其传递给 Model。ViewModel 不直接操作 View,而是通过数据绑定和命令机制进行交互。
43+
44+
- **职责**
45+
- 提供 View 所需的数据。
46+
- 响应 View 的用户操作,并将操作传递给 Model。
47+
- 实现双向数据绑定,使得 View 和 Model 之间保持同步。
48+
49+
50+
### MVVM 的工作原理
51+
52+
MVVM 的工作原理是通过数据绑定实现视图和模型的同步。视图层(View)直接绑定到 ViewModel 中的属性,这样当 ViewModel 中的数据发生变化时,视图会自动更新。同时,视图的用户输入会通过绑定机制传递给 ViewModel,ViewModel 再更新 Model。
53+
54+
- **单向绑定**:ViewModel 到 View 的数据流动。当 ViewModel 中的数据发生变化时,View 自动更新。
55+
- **双向绑定**:View 到 ViewModel 的数据流动也同步。例如,用户在表单中输入数据时,ViewModel 会自动更新。
56+
57+
### MVVM 与 MVC、MVP 的对比
58+
59+
- **MVC(Model-View-Controller)**:MVC 中,控制器(Controller)负责响应用户交互并更新模型(Model)。视图(View)观察模型,并根据模型的变化进行更新。MVC 的控制器承担了较多的业务逻辑处理工作。
60+
61+
- **MVP(Model-View-Presenter)**:MVP 中,Presenter 是负责视图与模型之间通信的中介,View 不直接依赖 Model。Presenter 包含了 UI 逻辑和交互逻辑,处理用户事件,并与 Model 交互。
62+
63+
- **MVVM**:MVVM 的核心是 ViewModel,它将 Model 和 View 进行解耦。View 和 ViewModel 通过数据绑定机制进行通信,View 只关注界面展示,ViewModel 负责处理逻辑。
64+
65+
**对比总结**
66+
- **解耦程度**:MVVM 提高了 View 和 Model 的解耦程度,尤其在数据绑定方面更为自动化和灵活。
67+
- **代码维护**:由于 ViewModel 仅处理与 UI 逻辑相关的部分,Model 专注于业务逻辑,这使得 MVVM 在代码的分离和维护性方面优于 MVC 和 MVP。
68+
- **适用场景**:MVVM 更适合需要复杂数据绑定和动态 UI 更新的应用,特别是在现代前端框架(如 Vue、Angular)中应用广泛。
69+
70+
### MVVM 的优缺点
71+
72+
#### 优点:
73+
- **解耦性好**:View 和 Model 之间没有直接的依赖关系,二者通过 ViewModel 进行沟通,代码更具模块化。
74+
- **可测试性强**:由于 ViewModel 独立于 View,业务逻辑和数据处理部分可以通过单元测试进行验证,而不依赖于实际的 UI。
75+
- **数据绑定机制**:数据绑定使得 View 和 ViewModel 之间的同步更加方便,减少了手动操作 DOM 的代码。
76+
77+
#### 缺点:
78+
- **学习成本高**:对于初学者来说,理解 MVVM 的数据绑定和通信机制可能有一定的难度。
79+
- **性能问题**:在复杂的场景下,大量的数据绑定可能会引起性能问题,尤其是在数据变更频繁的情况下。
80+
- **调试难度增加**:由于数据绑定是自动化的,可能导致调试过程变得更加复杂,不易跟踪数据的流动。
81+
82+
### MVVM 应用示例:使用 Vue.js
83+
84+
Vue.js 是一种典型的 MVVM 框架,下面展示了一个简单的 Vue.js 示例,展示 MVVM 的工作原理。
85+
86+
```html
87+
<div id="app">
88+
<input v-model="name" placeholder="Enter your name">
89+
<p>Hello, {{ name }}!</p>
90+
</div>
91+
92+
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
93+
<script>
94+
new Vue({
95+
el: '#app',
96+
data: {
97+
name: ''
98+
}
99+
});
100+
</script>
101+
```
102+
103+
在这个示例中:
104+
- **Model**`data` 对象中存储的 `name` 字段。
105+
- **View**:HTML 模板中展示数据的部分,如 `input``p` 标签。
106+
- **ViewModel**:Vue 实例管理的数据和行为,负责与 View 的数据绑定和交互。
107+
108+
当用户在输入框中输入数据时,`v-model` 会自动更新 `data` 中的 `name`,并且由于数据绑定,`{{ name }}` 会同步更新到页面上。
109+
110+
### 总结
111+
112+
MVVM 模式通过数据绑定机制,将 View 和 Model 进行解耦,使得前端开发中的数据管理和 UI 渲染变得更加高效。它非常适合需要频繁更新 UI 的应用,尤其在现代前端开发框架中广泛应用。虽然 MVVM 提供了很好的解耦性和可维护性,但也带来了性能和调试方面的挑战,因此在应用时需要根据具体情况权衡。

src/design/9 model_view_in_qt.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
---
2+
title: Model-View 框架
3+
order: 2
4+
category:
5+
- 架构设计
6+
tag:
7+
- 设计模式
8+
- Model-View
9+
- Qt
10+
editLink: false
11+
---
12+
13+
Qt 的 Model-View 框架是一种用于处理和显示数据的灵活机制,特别适合需要在用户界面中展示大量或复杂数据的应用程序。通过将数据和显示逻辑解耦,Model-View 框架提供了更高的灵活性和可维护性。Qt 的 Model-View 框架包含三个主要组件:Model(模型)、View(视图)和 Delegate(委托)。
14+
15+
### Model-View 框架的核心概念
16+
17+
#### Model(模型)
18+
19+
Model 是数据的抽象表示,负责存储和管理数据,并向 View 提供访问这些数据的接口。Model 不直接与 UI 打交道,而是通过信号和槽机制通知 View 数据的变化。Qt 提供了几个现成的模型类,如 `QStandardItemModel``QStringListModel`,开发者也可以通过继承 `QAbstractItemModel``QAbstractTableModel``QAbstractListModel` 来自定义模型。
20+
21+
**Model 的主要职责**
22+
- **管理数据**:模型负责存储和管理数据,包括对数据的增删改查操作。
23+
- **提供接口**:模型通过标准化的接口提供数据给 View。
24+
- **通知数据变更**:模型会在数据发生变化时发出信号,通知 View 更新显示。
25+
26+
Qt 中常用的 Model 类:
27+
- **QAbstractItemModel**:所有自定义模型的基类,适合树状结构数据。
28+
- **QAbstractListModel**:用于一维列表数据的基类。
29+
- **QAbstractTableModel**:用于二维表格数据的基类。
30+
- **QStandardItemModel**:提供标准的项目模型,实现了表格和树状结构的支持。
31+
32+
**示例**:使用 `QStandardItemModel` 来存储和操作数据。
33+
```cpp
34+
QStandardItemModel *model = new QStandardItemModel();
35+
model->setHorizontalHeaderLabels({"Name", "Age"});
36+
37+
QStandardItem *item1 = new QStandardItem("John");
38+
QStandardItem *item2 = new QStandardItem("25");
39+
40+
model->appendRow({item1, item2});
41+
```
42+
43+
#### View(视图)
44+
45+
View 负责展示数据,是用户与数据进行交互的界面部分。View 通过访问 Model 提供的数据,并将这些数据渲染到屏幕上。常用的视图类包括 `QListView`、`QTableView` 和 `QTreeView`,它们分别用于显示列表、表格和树形数据。
46+
47+
**View 的主要职责**:
48+
- **显示数据**:View 从 Model 中获取数据并进行显示。
49+
- **用户交互**:View 处理用户的输入,如点击、编辑等。
50+
- **数据同步**:View 会自动更新显示,确保与 Model 数据保持一致。
51+
52+
Qt 中常用的 View 类:
53+
- **QListView**:用于显示列表数据。
54+
- **QTableView**:用于显示表格数据。
55+
- **QTreeView**:用于显示树形结构数据。
56+
57+
**示例**:使用 `QTableView` 显示 `QStandardItemModel` 的数据。
58+
```cpp
59+
QTableView *view = new QTableView();
60+
view->setModel(model);
61+
view->show();
62+
```
63+
64+
#### Delegate(委托)
65+
66+
Delegate 是 View 和 Model 之间的中介,用于定制数据的显示和编辑。通过委托,开发者可以控制单元格的外观和编辑方式。Qt 默认的委托类是 `QStyledItemDelegate`,你可以继承这个类来自定义数据的显示和编辑行为。
67+
68+
**Delegate 的主要职责**
69+
- **渲染数据**:委托负责将 Model 中的数据渲染为可视化的控件或元素。
70+
- **编辑数据**:委托还负责处理数据的编辑,提供自定义的编辑控件和逻辑。
71+
72+
**示例**:自定义委托,通过 `QStyledItemDelegate` 渲染数据。
73+
```cpp
74+
class CustomDelegate : public QStyledItemDelegate {
75+
Q_OBJECT
76+
77+
public:
78+
CustomDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}
79+
80+
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
81+
painter->save();
82+
// 自定义绘制逻辑
83+
painter->drawText(option.rect, Qt::AlignCenter, index.data().toString());
84+
painter->restore();
85+
}
86+
};
87+
88+
// 在视图中使用自定义委托
89+
view->setItemDelegate(new CustomDelegate());
90+
```
91+
92+
### Model-View 的数据流
93+
94+
Model-View 模式的关键在于数据与 UI 的分离,数据流的方向如下:
95+
1. **View 获取数据**:View 通过 `setModel()` 设置模型,并通过模型的标准接口(如 `data()`、`rowCount()`、`columnCount()`)获取数据并显示在界面上。
96+
2. **用户交互**:用户在 View 中进行操作(如点击、编辑),这些操作会通过委托发送到 Model,Model 根据操作更新数据。
97+
3. **Model 通知 View**:当 Model 数据发生变化时,Model 通过信号通知 View,View 自动刷新显示。
98+
99+
### 数据绑定与更新
100+
101+
在 Qt 的 Model-View 模式中,数据更新主要依赖于信号与槽机制。Model 通过 `dataChanged()` 等信号通知 View 数据已更改,View 会根据这些信号自动更新显示内容。常用的更新信号包括:
102+
- **dataChanged()**:当模型中的某个数据项发生变化时发出。
103+
- **layoutChanged()**:当模型的布局发生变化时发出,例如排序、筛选等操作。
104+
- **rowsInserted()**、**rowsRemoved()**:当插入或删除行时发出。
105+
106+
### Qt 中的 Model-View 与 MVC
107+
108+
Qt 的 Model-View 框架类似于传统的 MVC(Model-View-Controller)模式,但它没有显式的 Controller。Qt 的设计将 Controller 的职责分散到 View 和 Delegate 中:
109+
- **View**:负责展示数据,并处理用户交互。
110+
- **Delegate**:负责处理数据的呈现和编辑。
111+
112+
通过这种设计,Qt 的 Model-View 框架能够更加灵活地支持各种数据展示场景,开发者可以更自由地定制数据的显示和交互行为。
113+
114+
### 自定义模型
115+
116+
虽然 Qt 提供了多种现成的模型类,但在实际应用中,经常需要创建自定义模型,以适应复杂的数据结构和特定的业务需求。自定义模型需要继承 `QAbstractItemModel`、`QAbstractTableModel` 或 `QAbstractListModel`,并实现相关的接口方法。
117+
118+
**常见需要实现的方法**:
119+
- **rowCount()**:返回模型的行数。
120+
- **columnCount()**:返回模型的列数。
121+
- **data()**:返回指定索引处的数据。
122+
- **setData()**:用于修改指定索引处的数据。
123+
- **headerData()**:返回模型的表头数据。
124+
125+
**示例**:自定义一个简单的表格模型。
126+
```cpp
127+
class CustomTableModel : public QAbstractTableModel {
128+
Q_OBJECT
129+
130+
public:
131+
CustomTableModel(QObject *parent = nullptr) : QAbstractTableModel(parent) {}
132+
133+
int rowCount(const QModelIndex &parent = QModelIndex()) const override {
134+
return 5; // 5 行
135+
}
136+
137+
int columnCount(const QModelIndex &parent = QModelIndex()) const override {
138+
return 3; // 3 列
139+
}
140+
141+
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
142+
if (role == Qt::DisplayRole) {
143+
return QString("Row%1, Column%2").arg(index.row()).arg(index.column());
144+
}
145+
return QVariant();
146+
}
147+
};
148+
```
149+
150+
### 代理模型
151+
152+
Qt 提供了一些代理模型(Proxy Model)来对原始模型的数据进行转换或过滤。常用的代理模型有:
153+
- **QSortFilterProxyModel**:用于对数据进行排序和过滤。
154+
- **QIdentityProxyModel**:直接映射原始模型,适合做数据的装饰或修改。
155+
156+
使用代理模型可以在不修改原始模型的情况下,对数据进行排序、过滤或其他转换操作。
157+
158+
**示例**:使用 `QSortFilterProxyModel` 进行排序。
159+
```cpp
160+
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel();
161+
proxyModel->setSourceModel(model);
162+
proxyModel->sort(0, Qt::AscendingOrder); // 对第 0 列进行升序排序
163+
164+
view->setModel(proxyModel);
165+
```
166+
167+
::: tip 总结
168+
169+
Qt 的 Model-View 框架通过将数据和显示逻辑解耦,提供了更高的灵活性和可维护性。无论是使用现成的模型类,还是通过自定义模型,开发者都能够以更清晰的方式管理复杂的数据展示和用户交互。通过委托机制,Qt 允许开发者定制数据的显示和编辑,使得 UI 的表现力更强。而代理模型则进一步扩展了数据处理的能力,使得数据的排序、过滤等操作更加方便。
170+
:::

src/other/2 encrypt_string.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@ category:
66
tag:
77
- c++
88
- constexpr
9+
- 逆向
910
editLink: false
1011
---
1112

12-
在现代编程中,保护敏感信息至关重要。常见的方法有运行时加密,但这种方式在某些情况下可能不足够安全,因为加密密钥和算法都可能在运行时暴露。为了解决这一问题,可以采用一种利用 `constexpr` 实现编译时加密,运行时解密的方法。本文将介绍这一技术,并展示一个具体的实现示例。
13+
介绍一种利用 `constexpr` 实现编译时加密,运行时解密的方法。本文将介绍这一技术,并展示一个具体的实现示例。
14+
::: tip
15+
逆向工程常通过执行文件的中静态字符串信息找到关键点函数进行逆向,编译时加密可以一定程度上避免这个问题。
16+
:::
1317

1418
### 什么是 [`constexpr`](https://en.cppreference.com/w/cpp/language/constexpr)
1519

@@ -63,7 +67,8 @@ private:
6367
}()
6468

6569
int main() {
66-
PROTECTED_STR("heng");
70+
PROTECTED_STR("heng");//编译后的执行文件中不存在‘heng’ 关键字符串信息
71+
// std::cout << "heng" << std::endl;// 编译后的执行文件包含有 ‘heng’ 关键字符串信息,提供逆袭的信息点
6772
return 0;
6873
}
6974
```
@@ -86,5 +91,5 @@ int main() {
8691
- 演示如何使用 `PROTECTED_STR` 宏来加密和解密字符串,并将解密后的字符串输出。
8792
8893
89-
利用 `constexpr` 实现编译时加密和运行时解密是一种有效保护敏感信息的方法。本文展示了该技术的一个具体实现示例,并详细解释了其工作原理和优点。通过这种方式,可以提高应用程序的安全性,防止敏感信息在编译后被轻易获取
94+
利用 `constexpr` 实现编译时加密和运行时解密是一种有效保护敏感信息的方法。本文展示了该技术的一个具体实现示例,并详细解释了其工作原理。通过这种方式,可以提高应用程序的安全性,避免给逆向提供敏感信息点
9095

0 commit comments

Comments
 (0)