Model(模型),是程序的主体部分,主要包含业务数据和业务逻辑。在模型层,还会涉及到用户发布的服务,在服务中会根据不同的业务需求,更新业务模型中的数据。
View(视图),是程序呈现给用户的部分,是用户和程序交互的接口,用户会根据具体的业务需求,在View视图层输入自己特定的业务数据,并通过界面的事件交互,将对应的输入参数提交给后台控制器进行处理。
Controller(控制器),Controller是用来处理用户输入数据,已经更新业务模型的部分。控制器中接收了用户与界面交互时传递过来的数据,并根据数据业务逻辑来执行服务的调用和更新业务模型的数据和状态。
一、MVC模式概述
模型-视图-控制器(MVC模式)是一种非常经典的软件架构模式,在UI框架和UI设计思路中扮演着非常重要的角色。从设计模式的角度来看,MVC模式是一种复合模式,它将多个设计模式在一种解决方案中结合起来,用来解决许多设计问题。MVC模式把用户界面交互分拆到不同的三种角色中,使应用程序被分成三个核心部件:Model(模型)、View(视图)、Control(控制器)。它们各自处理自己的任务:
(1)模型:模型持有所有的数据、状态和程序逻辑。模型独立于视图和控制器。
(2)视图:用来呈现模型。视图通常直接从模型中取得它需要显示的状态与数据。对于相同的信息可以有多个不同的显示形式或视图。
(3)控制器:位于视图和模型中间,负责接受用户的输入,将输入进行解析并反馈给模型,通常一个视图具有一个控制器。
MVC模式将它们分离以提高系统的灵活性和复用性,不使用MVC模式,用户界面设计往往将这些对象混在一起。MVC模式实现了模型和视图的分离,这带来了几个好处。
(1)一个模型提供不同的多个视图表现形式,也能够为一个模型创建新的视图而无须重写模型。一旦模型的数据发生变化,模型将通知有关的视图,每个视图相应地刷新自己。
(2)模型可复用。因为模型是独立于视图的,所以可以把一个模型独立地移植到新的平台工作。
(3)提高开发效率。在开发界面显示部分时,你仅仅需要考虑的是如何布局一个好的用户界面;开发模型时,你仅仅要考虑的是业务逻辑和数据维护,这样能使开发者专注于某一方面的开发,提高开发效率。
图1.1MVC模式结构图
如图1.1所示,视图中用户的输入被控制器解析后,控制器改变状态激活模型,模型根据业务逻辑维护数据,并通知视图数据发生变化,视图得到通知后从模型中获取数据刷新自己。
二、深入解析MVC模式
对MVC模式有了一个初步的认识之后,我们可以继续深入地了解它。MVC模式的关键是实现了视图和模型的分离。这是如何实现的呢?MVC模式通过建立一个“发布/订阅”(publish-subscribe)的机制来分离视图和模型。发布-订阅(publish-subscribe)机制的目标是发布者,它发出通知时并不需知道谁是它的观察者。可以有任意数目的观察者订阅并接收通知。MVC模式最重要的是用到了Observer(观察者模式),正是观察者模式实现了发布-订阅(publish-subscribe)机制,实现了视图和模型的分离。因此谈到MVC模式就必须谈到观察者模式。如图2.1所示。
图2.1 观察者模式
观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
图2.1中Subject我们称为主题,Observer称为观察者。主题提供注册观察者、移除观察者和通知观察者的接口,这样只要观察者注册成为主题的一个观察者的话,主题在状态发生变化时会通知观察者。观察者有一个更新自己的接口,当收到主题的通知之后观察者就会调用该接口更新自己。如何实现注册和通知的呢?如果是用C++或java的话,主题就需要有一个观察者链表,注册就是将观察者加入到该链表中,移除则是从该链表中删除,当主题状态变化时就遍历该链表所有的观察者通知它们更新自己。在c#中可以通过委托实现注册。
控制器相当于是视图的行为,我们还要考虑到今后可能面临的变化,例如视图想换一种行为,我们是否做好了应付这种变化的准备呢?我们不应该将视图和控制器紧耦合,例如不要一开始就将视图和某一个具体行为绑定起来,这样会使视图更换行为的时候变得很困难,我们应该能动态的给视图指定一个行为,用多态使视图和控制器之间松耦合,可以使视图轻松地更换行为,于是策略模式登场了,策略模式正是用来解决这个问题的。如图2.2所示。
图2.2策略模式
三、MVC模式的应用
图3.1 命令模式
命令模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。
根据项目的需求:用户可以通过工具条按钮、菜单按钮、对话框按钮或鼠标右键等操作来执行同一项请求;支持取消和重做操作;很容易增加或更换新的命令请求。这些问题都可以通过命令模式来解决。命令模式可以使不同地方的按钮或操作代表同一项功能,只需要让它们共享响应具体Command子类的同一实例即可。还可以通过多态动态替换Command对象从而轻松地更换请求命令。Command的Execute操作可在实施操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。Command具体对象调用一个Unexecute操作,该操作取消上一次Execute调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用Unexecute和Execute来实现次数不限的“取消”和“重做”。Command模式将调用操作的对象与知道如何实现该操作的对象解耦。Command可像其他的对象一样被方便的替换和扩展。在菜单中增加新的调用命令时只要增加新的Command,而无需改变已有的类。我们将Command对象放到控制器中,控制器接收视图的输入并解析,将用户输入发送给Command对象,Command对象调用执行接口,然后在Command子类中将用户输入发给模型,模型执行逻辑维护数据,并通知视图。视图得到通知后获取模型的新数据并更新自己。项目的界面框架采用这种MVC模式使得软件变得灵活、易于扩展和维护。
四、结论
在软件开发的过程中,开发人员最为担心的是需求的不断变化,而这些变化又不是开发人员所能控制的,因此,为了适应这些变化,就要使用设计模式。MVC模式在一个解决方案中综合运用多种设计模式,是模式中的模式,按MVC模式的设计,一个模型可以表现为多个视图,这样可以减少代码的冗余。模型返回的数据不带任何显示格式,因此这些模型也可直接应用于接口的使用。由于一个应用程序被分离为三层,因此有时改变其中的一层就能满足应用的改变。一个应用的业务流程或者业务规则的改变只需改动MVC的模型层,而不会影响到视图和控制器。不过,使用设计模式并不是一定就能得到一个好的设计,过分地使用设计模式会增加程序的复杂性和晦涩性,让程序不易理解,从而降低了程序的易维护性。因此要避免过度使用设计模式,我们应根据面向对象的设计原则和实际情况综合考虑我们的设计,从而设计出具有良好扩展性和易维护性的软件。