模型 - 视图 - 控制器(MVC)详解

模型视图控制器(MVC)一个至关实用且十分流行的设计模式。做为一位称职码农,你不可能没据说过吧。 不幸的是它难以让人理解。 在本文中,我将给出我认为是MVC的最简单的解释,以及为何你应该使用它。redis

什么是模型 - 视图 - 控制器(MVC)?

在一个典型应用中,你会发现这三个基本组成部分:设计模式

  • 数据(模型)
  • 查看和修改数据的接口(视图)
  • 能够对数据施加的操做(控制器)

MVC模式,简言之,就是:工具

  1. 模型表明数据,除此以外别无它用。 模型不依赖于控制器或视图。布局

  2. 视图显示模型数据,发送用户动做(例如按钮点击)到控制器。 视图能够this

    • 独立于模型和控制器的; 或者spa

    • 做为控制器,所以依赖于模型。翻译

  3. 控制器提供模型数据至视图,解释用户的行为,如按钮的点击。 控制器依赖于视图和模型。 在一些状况下,控制器和视图能够合二为一。设计

规则1是MVC的黄金法则,我再重复一遍:code

模型表明数据,除此以外别无它用。 模型不依赖于控制器或视图。对象

以一个地址簿应用程序为例。 模型是一些Person对象,视图是一个GUI窗口,显示联系人列表,而且控制器处理用户行为诸如“删除联系人”,“添加联系人”,“发邮件至联系人”等。下面的例子没有使用MVC,由于模型依赖于视图。

//Example 1:
void Person::setPicture(Picture pict){
    m_picture = pict; //set the member variable
    m_listView->reloadData(); //update the view
}

下面的示例使用了MVC:

//Example 2:
void Person::setPicture(Picture pict){
    m_picture = pict; //set the member variable
}

void PersonListController::changePictureAtIndex(Picture newPict, int personIndex){
    m_personList[personIndex].setPicture(newPict); //modify the model
    m_listView->reloadData(); //update the view
}

在上面的例子中, Person类并不知道视图的存在。 PersonListController负责模型修改和视图更新。视图窗口告诉控制器用户的行为(就上述状况而言,它将提醒控制器用户修改了一个联系人的照片)。

MVC的优点在哪里?

没必要要的复杂性是软件开发的梦魇。 它致使软件漏洞百出,维护费用昂贵。而处处引入依赖很容易就会形成代码过于复杂。 相反地,若是咱们移除没必要要的依赖能够改善代码质量,维护上更容易,由于代码可重复使用而无需修改。 你能够安心地复用旧的、稳定的代码不用顾虑招致新的bug。

MVC设计模式的主要优势是:

MVC使得模型类不加修改便可重复使用。

控制器存在的目的是消除模型与视图依赖关系。 从模型中移除视图依赖后,模型代码变得整洁起来。

为何模型代码能这么小清新? 让咱们继续以地址簿应用为例。 项目经理找到码农们,对他们说 ”我很欣赏联系人列表窗口,但咱们须要另外一个窗口显示全部联系人的照片,这些照片应该是处于一个表格布局中,每排五张照片。”

若是应用程序采用了MVC,这个任务至关简单。 目前主要有三个类: Person  PersonListControllerPersonListView。 还须要建立两个类: PersonPhotoGridViewPersonPhotoGridController 。 Person类保持不变的状况下,很容易插入两种不一样的视图。 怎么样啊!

若是应用程序具备例1中相似的结构,任务立马变得棘手了。此时有两个类Person 和PersonListView 。Person类不能插入另外一种视图,由于它包含了涉及PersonListView类的具体代码 。 开发人员必须修改Person类以适应新的PersonPhotoGridView ,并最终像这样复杂化模型:

//Example 3:
void Person::setPicture(Picture pict){
    m_picture = pict; //set the member variable
    if(m_listView){ //check if it's in a list view
        m_listView->reloadData(); //update the list view
    }
    if(m_gridView){ //check if it's in a grid view
        m_gridView->reloadData(); //update the grid view
    }
}

如你所观察到的同样,模型代码开始变得苦涩。 若是项目经理接着发话:“咱们正在移植的应用程序到一个使用不一样的GUI库的平台”,简洁性此时尤其突出。 采用MVC的Person类能够经过不一样的GUI工具包显示无需任何修改。 单单建立一个控制器,并用新的库中的视图,就像你用旧的库同样。 若是没有MVC,支持多种GUI工具包将是一场噩梦。 最终代码可能会这样的:

//Example 4:
void Person::setPicture(Picture pict){
    m_picture = pict;
#ifdef ORIGINAL_GUI_TOOLKIT
    if(m_listView){ //check if it's in a list view
        m_listView->reloadData(); //update the list view
    }
    if(m_gridView){ //check if it's in a grid view
        m_gridView->reloadData(); //update the grid view
    }
#endif
#ifdef NEW_GUI_TOOLKIT
    if(m_listView){ //check if it's in a list view
        m_listView->redisplayData(); //update the list view
    }
    if(m_gridView){ //check if it's in a grid view
        m_gridView->redisplayData(); //update the grid view
    }
#endif
}

setPicture方法基本上会乱上一团。

为何不把控制器代码置入视图?

一直解决例4中的尴尬代码的方案是将控制器代码从模型移动到视图,像这样:

//Example 5:
PersonListView::newPictureClicked(Picture clickedPicture){
    m_selectedPerson.setPicture(clickedPicture);
    this->reloadData();
}

上述例子也可以使模型易于复用,这是MVC的主要优点。 当视图将只显示一种类型的模型对象,合并视图和控制器是比较合适的。 例如,一个SinglePersonView将只显示一个Person的对象,因此SinglePersonView可兼做控制器。

然而,若是控制器与视图分离,MVC有第二个优势:

MVC可使视图可重复使用的而无需修改。

MVC模型不只使得模型简洁,视图一样如此。 理想状况下,列表视图应该可以显示的任何列表,不仅是Person的对象。 例5中的代码不能是一个通用的列表视图,由于它与模型耦合在一块儿(Person类)。要想视图(如列表视图,或表格视图)和模型代码同时可重复使用,MVC是惟一的选择。 控制器移除模型和视图间的依赖关系,这使得它们在其余地方能够被复用。

结论

MVC设计模式在视图和模型间插入控制器类,移除视图和模型间的依赖。 模型以及视图,可重复使用而无需修改。 这样,实现新的功能和维护变得垂手可得。 该用户很快获得稳定的软件,该公司节省了资金,并且开发人员不发疯。 这样好不?

翻译来源:http://www.tomdalling.com/blog/software-design/model-view-controller-explained/

相关文章
相关标签/搜索