参考资料:
MVC 模式 |
MVC设计模式介绍 & SpringMVC实现 - 掘金
MVC设计模式 - 掘金
MVC开发Web应用程序,实现项目的MVC结构设计和搭建,精讲教程无废话
MVC(Model-View-Controller)是一种经典的软件架构设计模式,用于组织和管理应用程序的代码。它将应用程序分为三个主要组件,每个组件都有不同的责任,以促进代码的可维护性和可扩展性。以下是MVC模式的三个主要组件及其职责:
-
Model(模型):
- 模型代表应用程序的数据和业务逻辑。
- 它负责存储、检索、更新和操作数据。
- 模型通常不直接与用户界面交互,而是通过控制器来实现。
-
View(视图):
- 视图是用户界面的表示,它负责将模型的数据呈现给用户。
- 视图通常是被动的,只负责显示数据,不进行处理或修改。
- 可以有多个不同的视图来呈现相同的数据,以适应不同的用户界面需求。
-
Controller(控制器):
- 控制器充当模型和视图之间的协调者,负责接收用户输入、处理用户请求并更新模型和视图。
- 它将用户的操作映射到模型上的相应操作,然后通知视图更新以反映最新的数据。
- 控制器通常包含应用程序的业务逻辑和控制流程。
MVC模式的主要优点包括:
- 分离关注点:MVC将应用程序分解成三个独立的组件,每个组件都有不同的职责,使得代码更易于理解和维护。
- 可扩展性:由于各个组件相对独立,可以更容易地添加新的功能或更改现有的功能,而不会影响其他部分的代码。
- 重用性:模型、视图和控制器的分离使得这些组件可以在不同的上下文中重复使用。
除此之外与之相关的设计模式还有很多。
-
MVVM(Model-View-ViewModel):
- MVVM是一种用于构建用户界面的设计模式,特别适用于前端开发和现代Web应用程序。它引入了ViewModel层,该层负责管理视图和模型之间的数据绑定。Angular和Vue.js等JavaScript框架广泛使用MVVM模式。
-
MVP(Model-View-Presenter):
- MVP是另一种用于构建用户界面的设计模式,它在模型、视图和控制器之间引入了Presenter层。Presenter负责处理用户输入,更新模型和控制视图的呈现。GWT(Google Web Toolkit)和WinForms等技术通常使用MVP。
-
Flux和Redux:
- 这是一种用于构建前端Web应用程序的模式,特别适用于单页面应用(SPA)。Flux和Redux采用了单向数据流的思想,将应用程序状态存储在单一的存储容器中,并使用纯函数来管理状态的变化和更新视图。
-
VIPER(View-Interactor-Presenter-Entity-Routing):
- VIPER是一种用于构建iOS应用程序的设计模式,它引入了多个组件,包括Interactor和Entity,以更好地管理应用程序的逻辑和状态。
-
CQRS(Command Query Responsibility Segregation):
- CQRS模式将读取和写入操作分开,以优化性能和可扩展性。它通常用于构建大规模、高并发的应用程序。
-
Actor模型:
- Actor模型是一种并发计算模型,它基于消息传递和封装状态的思想。它适用于构建高度并发的系统,例如分布式系统和通信系统。
-
Data-Driven设计模式:
- 这是一种强调数据驱动应用程序行为的设计模式,通常用于游戏开发和可视化应用程序。
//数据相关 都放到 M
const m = {
data: {
// 初始化数据n,从本地数据库拿到的数字n
n: parseInt(localStorage.getItem('n'))
},
create(){},
delete(){},
update(data){
Object.assign(m.data, data)
eventBus.trigger('m:updated')
localStorage.setItem('n', m.data.n)
},
get(){}
}
//视图相关 都放到 V
const v = {
el: null,
html: `
<div>
<div class="output">
<span id="number">{{n}}</span>
</div>
<div>
<button id="add1">+1</button>
<button id="minus1">-1</button>
<button id="mul2">×2</button>
<button id="divide2">÷2</button>
</div>
</div>
`,
// 初始化html
init(container){
v.el = $(container)
},
// 将数据渲染到页面
render(n){
if(v.el.children.length === null){ // 如果没有渲染过
} else {
v.el.empty()
}
$(v.html.replace('{{n}}', n)).appendTo(v.el)
},
}
//其他 都 C
const c = {
init(container){
v.init(container) // 第一次渲染html
v.render(m.data.n) // 第一次 view = render(data)
c.autoBindEvents() // 绑定事件
eventBus.on('m:updated', ()=>{
v.render(m.data.n)
})
},
events: {
'click #add1': 'add',
'click #minus1': 'minus',
'click #mul2': 'mul',
'click #divide2': 'div'
},
autoBindEvents(){
for(let key in c.events){
const value = c[c.events[key]]
const spaceIndex = key.indexOf(' ')
const part1 = key.slice(0, spaceIndex)
const part2 = key.slice(spaceIndex+1)
v.el.on(part1, part2, value)
}
},
add(){
m.update({n: m.data.n + 1})
},
minus(){
m.update({n: m.data.n - 1})
},
mul(){
m.update({n: m.data.n * 2})
},
div(){
m.update({n: m.data.n / 2})
}
}