模式与架构系列之一:MVC

1.MVC架构

Model-View-Controller (MVC) 架构模式,可以分解为以下三个部件:

模型:封装业务逻辑;

视图:即界面(这里不啃概念)

控制器:在视图与控制器间传递消息,使模型和视图协调工作。

 

理想状况下,这种架构模式带来的好处是令人心动的。由于界面与业务逻辑的分离,降低了依赖性,使得逻辑代码可以完整地、轻松地被摘下来,用于别处。同时,控制器使用消息分发,可以轻易实现同时对多个界面产生影响。当然,这是理想状况

 

2.一个MVC示例
MVC模块的简要类图:


 


 


 


 


1ModelElemen类实现ISenderIReceiver接口,可发送及接收消息,作为Model类的基类;
2ViewElement类继承自Form类,并实现ISenderIReceiver接口,可发送及接收消息,作为View类的基类;
3ControllerElement类实现ISenderIReceiverIController接口,可发送、接收及分发消息,作为Controller类的基类。

 

配置文件:

为了控制器最终能正确有效地向特定的一个或若干个ViewModel分发消息,系统用一个XML文件用于保存ModelViewController三者的关系,即完成所谓“注册”的功能,该XML文件结构类似如下:

  <ElementDefinetion>

<FullName>xxProj.MainForm</FullName>

<ShortName>MainForm</ShortName>

<AssemblyName> xxProj </AssemblyName>

<BelongedController>IndiController</BelongedController>

<Type>View</Type>

  </ElementDefinetion>

  <ElementDefinetion>

    <FullName> xxProj.ActiveGrpCallList</FullName>

    <ShortName>ActiveGrpCallList</ShortName>

    <AssemblyName> xxProj </AssemblyName>

    <BelongedController>GrpCallController</BelongedController>

    <Type>View</Type>

  </ElementDefinetion>

  <ElementDefinetion>

    <FullName> xxProj.IndiCallModel</FullName>

    <ShortName>IndiCallModel</ShortName>

    <AssemblyName> xxProj </AssemblyName>

    <BelongedController>IndiController</BelongedController>

    <Type>Model</Type>

  </ElementDefinetion>

  <ElementDefinetion>

    <FullName> xxProj.GrpCallModel</FullName>

    <ShortName>GrpCallModel</ShortName>

    <AssemblyName> xxProj </AssemblyName>

    <BelongedController>GrpCallController</BelongedController>

    <Type>Model</Type>

  </ElementDefinetion>

…………

 

MVC模式下消息传递流程:
下面是一个操作的消息传递(调用)流程:


 


 


 


 


 

该操作的实际代码类似如下:

主界面(ViewMainForm中:

private void StartSchemaToolStripMenuItem_Click(object sender, EventArgs e)

{

this.SendMsg("MainForm.StartSchema", null);

}

 

MainForm的父类ViewElement中,SendMsg()方法实际上是通过一个被称为“发送代理SendProxy来发出消息:

public ObjectDictionary SendMsg(string strMsgHeader, ObjectDictionary dicMsgContent)

{

       return this.SendProxy.SendMsg(strMsgHeader,dicMsgContent);

}

 

在发送代理SendProxy中,调用MainForm所属的控制器的DistributeMsg()方法:

public ObjectDictionary SendMsg(string strMsgHeader, ObjectDictionary dicMsgContent)

{

return this.Controller.DistributeMsg(strMsgHeader,dicMsgContent);

}

 

MainForm所属的控制器IndiController中,方法DistributeMsg()具有如下代码

public override ObjectDictionary DistributeMsg(string strMsgHeader, ObjectDictionary dicMsgContent)

{

try

{

switch (strMsgHeader)

{

case "MainForm.StartSchema":

this.ElementFactory.GetView("StartSchemaWizard1Form").ReceiveMsg("StartSchemaWizard1Form.StartSchem", dicMsgContent);

return null;

……

}

}

}

 

其中ElementFactory.GetView("StartSchemaWizard1Form")利用C#中的反射机制返回类

StartSchemaWizard1Form的一个对象(此时须用到上述的XML配置文件,以便在构造对象时传入其所属的控制器)。最终实现界面变化的代码则位于目标View(即StartSchemaWizard1Form)的ReceiveMsg()方法中,这样,一个操作最终完成。

 

public override ObjectDictionary ReceiveMsg(string strMsgHeader, ObjectDictionary

dicMsgContent)

{

switch (strMsgHeader)

{

case "StartSchemaWizard1Form.StartSchem":

//界面变化

……

break;

……

}

return null;

}

 

 

3.最后

以上示例是曾经被实际应用过的MVC,写作的人恐怕也是参考了网上的例子,所以可能难免有些似曾相识。

 

关于它的消息流程,你也可以很直白地将它理解为:将一个直接的函数调用拆分为两步,先调用控制器的相应方法,再经由控制器调用位于视图中的方法。(或者从视图到控制器到模型)

 

所谓的消息,不过是些字符串,通过这些字符串来标识所要调用的目标。

 

我在使用过程中遇到一个比较明显的问题,那就是调试,远不如分层架构那么直观,特别是当由控制器分发出来的是“异步消息(所谓异步即消息发出之后直接返回,不需等待目标方法完成)时,更加难以跟踪调试。当然,这可能跟架构作者和使用者的编程水平都有关系。

菜鸟我对MVC的理解还是比较肤浅的,只是简单说说自己看到的和自己体会到的,大大们多多批评指正,万勿笑话。

 

原文地址:https://www.cnblogs.com/morvenhuang/p/632307.html