模式与架构系列之一:MVC
Model-View-Controller (MVC) 架构模式,可以分解为以下三个部件:
模型:封装业务逻辑;
视图:即界面(这里不啃概念);
控制器:在视图与控制器间传递消息,使模型和视图协调工作。
在理想状况下,这种架构模式带来的好处是令人心动的。由于界面与业务逻辑的分离,降低了依赖性,使得逻辑代码可以完整地、轻松地被摘下来,用于别处。同时,控制器使用消息分发,可以轻易实现同时对多个界面产生影响。当然,这是理想状况。
(1)ModelElemen类实现ISender、IReceiver接口,可发送及接收消息,作为Model类的基类;
(2)ViewElement类继承自Form类,并实现ISender、IReceiver接口,可发送及接收消息,作为View类的基类;
(3)ControllerElement类实现ISender、IReceiver、IController接口,可发送、接收及分发消息,作为Controller类的基类。
配置文件:
为了控制器最终能正确有效地向特定的一个或若干个View或Model分发消息,系统用一个XML文件用于保存Model、View、Controller三者的关系,即完成所谓“注册”的功能,该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模式下消息传递流程:
下面是一个操作的消息传递(调用)流程:
该操作的实际代码类似如下:
主界面(View)MainForm中:
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的理解还是比较肤浅的,只是简单说说自己看到的和自己体会到的,大大们多多批评指正,万勿笑话。
关注作者:欢迎扫码关注公众号「后厂村思维导图馆」,获取本人自建的免费ChatGPT跳板地址,长期有效。 原文链接:https://www.cnblogs.com/morvenhuang/archive/2007/01/28/632307.html 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文链接,否则保留追究法律责任的权利。 |