MVC还是MVVM?或许VMVC更适合WinForm客户端
最近开始重构一个稍嫌古老的C/S项目,原先采用的技术栈是『WinForm』+『WCF』+『EF』。相对于现在铺天盖地的B/S架构来说,看上去似乎和Win95一样古老,很多新入行的,可能就没有见过经典的C/S架构的系统。事实上,作为企业信息管理系统,包括ERP/CRM/SCM等,桌面客户端还是很OK的。
这次重构原定的目标有两个:
1、客户端还是WinForm不变,但使用MVC模式重写;
2、WCF改成WebAPI。
经过2周时间的尝试和探索,重构计划变更为:
1、使用VMVC模式来重构WinForm客户端;
2、用WCF实现伪WebAPI,其本质还是个WCF服务,但实现了RESTful风格的WebAPI。
这次和大家分享我对客户端架构的一些探索,就不展开服务端相关的话题了。那么,什么是VMVC呢?呵呵,这个是我发明的新名称,和MVC的区别在于用ViewModel替换了Model。ViewModel和View之间实现双向数据绑定,View上面的交互产生的操作指令,还是由Controller接收,然后通过对ViewModel的操作,更新View的数据。
简单地说,就是ViewModel负责数据流,View负责显示和接受用户指令,而Controller则居中调度。示意图如下:

由于实现了数据双向绑定,所以在一定程度上简化了数据的存储。只需要执行ViewModel上的Save()方法,就可以将新的数据通过WebAPI存储到数据库了。
ViewModel的职责非常明确,就是一个数据流引擎!所以基本上都是Load()、Save()、Show()、Refresh()、Close()这些无脑方法,一丁点的业务逻辑都木有。非常适合有一定编程经验,但不了解业务逻辑的程序员编写。
而View就更简单了,完全由VS的窗体设计器生成。UI设计师从此不需要PS了,根据产品原型直接拖控件就OK。
最后,所有的业务逻辑都写在Controller里面,这样就为自动化测试提供了可能。测试工程师只需要编写一段测试代码替代Controller,同时对View的数据进行注入就可以跑单元测试。
下面是我用于尝试这种模式的示例,希望能够起到抛砖引玉的作用。
代码结构:

Controller(部分代码),通过订阅View上面的确定按钮点击事件实现用户操作的委托:
/// <summary>
/// 修改服务器配置
/// </summary>
private void ConfigServer()
{
_SetModel = new SetModel(); // 订阅确定按钮点击事件
_SetModel.View.ConfirmButton.Click += SetConfirm_Click;
_SetModel.ShowDialog();
} /// <summary>
/// 点击确定按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SetConfirm_Click(object sender, EventArgs e)
{
if (!_SetModel.Test()) return; _SetModel.Save();
_SetModel.Close();
}
ViewModel:
using System;
using System.Windows.Forms;
using Insight.Utils.Client;
using Insight.Utils.Common;
using Insight.WS.Client.Common.Utils;
using Insight.WS.Client.MainApp.Views; namespace Insight.WS.Client.MainApp.Models
{
public class SetModel
{
public LoginSet View = new LoginSet(); private string _Address = Config.BaseAddress();
private string _Port = Config.Port();
private bool _SaveUser = Config.IsSaveUserInfo(); /// <summary>
/// 构造方法,初始化控件初始值
/// 通过订阅事件实现双向数据绑定
/// </summary>
public SetModel()
{
View.AddressInput.EditValueChanged += AddressChanged;
View.AddressInput.Text = _Address; View.PortInput.EditValueChanged += PortChanged;
View.PortInput.Text = _Port; View.SaveUserCheckBox.CheckStateChanged += SaveUserChanged;
View.SaveUserCheckBox.Checked = _SaveUser;
} /// <summary>
/// 显示对话框
/// </summary>
public void ShowDialog()
{
View.ShowDialog();
} /// <summary>
/// 关闭对话框
/// </summary>
public void Close()
{
View.DialogResult = DialogResult.OK;
View.Close();
} /// <summary>
/// 测试服务器连通性
/// </summary>
/// <returns>bool 是否通过连通性测试</returns>
public bool Test()
{
var url = $"http://{_Address}:{_Port}/commonapi/v1.0/test";
var result = new HttpClient(url).Request(Params.Token);
if (result.Code != "") return true; Messages.ShowError("请配置正确的服务器地址和端口号!");
return false;
} /// <summary>
/// 保存设置
/// </summary>
public void Save()
{
if (!_SaveUser) Config.SaveUserName(string.Empty); Config.SaveIsSaveUserInfo(_SaveUser);
Config.SaveAddress(_Address, _Port); Params.InsightServer = $"http://{_Address}:{_Port}";
} /// <summary>
/// 服务器地址发生变化
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AddressChanged(object sender, EventArgs e)
{
_Address = View.AddressInput.Text;
} /// <summary>
/// 服务端口发生变化
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PortChanged(object sender, EventArgs e)
{
_Port = View.PortInput.Text;
} /// <summary>
/// 保存用户账号选项发生变化
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SaveUserChanged(object sender, EventArgs e)
{
_SaveUser = View.SaveUserCheckBox.Checked;
}
}
}
MVC还是MVVM?或许VMVC更适合WinForm客户端的更多相关文章
- 还在纠结 Flux 或 Relay,或许 Redux 更适合你
重磅消息,Redux 1.0 发布,终于可以放心用于生产环境了! 在这个端应用技术膨胀的时代,每天都有一大堆框架冒出,号称解决了 XYZ 等一系列牛 X 的问题,然后过一段时间就不被提起了.但开发的应 ...
- Android App的设计架构:MVC,MVP,MVVM与架构经验谈
相关:http://www.cnblogs.com/wytiger/p/5996876.html 和MVC框架模式一样,Model模型处理数据代码不变在Android的App开发中,很多人经常会头疼于 ...
- MVC, MVP, MVVM比较以及区别(下)
上一篇得到大家的关注,非常感谢.一些朋友评论中,希望快点出下一篇.由于自己对于这些模式的理解也是有限,所以这一篇来得迟了一些.对于这些模式的比较,是结合自己的理解,一些地方不一定准确,但是只有亮出自己 ...
- MVC, MVP, MVVM比较以及区别
MVC, MVP和MVVM都是用来解决界面呈现和逻辑代码分离而出现的模式.以前只是对它们有部分的了解,没有深入的研究过,对于一些里面的概念和区别也是一知半解.现在一边查资料,并结合自己的理解,来谈一下 ...
- 浅析前端开发中的 MVC/MVP/MVVM 模式
MVC,MVP和MVVM都是常见的软件架构设计模式(Architectural Pattern),它通过分离关注点来改进代码的组织方式.不同于设计模式(Design Pattern),只是为了解决一类 ...
- [转]MVVM架构~mvc,mvp,mvvm大话开篇
MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负 责显示.作为一种新的模式,MVP与MVC有着一 ...
- MVC,MVVM,MVP等设计模式的分析
从Script到Code Blocks.Code Behind到MVC.MVP.MVVM 三个模式按照大致的历史进程将这些概念进行划分: Script Code Blocks.Code Behind ...
- 前端mvc mvp mvvm 架构介绍(vue重构项目一)
首先 我们为什么重构这个项目 1:我们现有的技术是前后台不分离,页面上采用esayUI+jq构成的单页面,每个所谓的单页面都是从后台胜场的唯一Id 与前端绑定,即使你找到了那个页面元素,也找不到所在的 ...
- 浅谈MVC、MVVM的区别
一.概述 MVC,MVP,MVVM是三种常见的前端架构模式(Architectural Pattern),它通过分离关注点来改进代码组织方式.不同于设计模式(Design Pattern),只是为了解 ...
随机推荐
- python3 threading初体验
python3中thread模块已被废弃,不能在使用thread模块,为了兼容性,python3将thread命名为_thread.python3中我们可以使用threading进行代替. threa ...
- AutoMapper
什么是AutoMapper? AutoMapper是一个对象和对象间的映射器.对象与对象的映射是通过转变一种类型的输入对象为一种不同类型的输出对象工作的.让AutoMapper有意思的地方在于它提供了 ...
- ExtJS 4.2 业务开发(一)主页搭建
本篇开始搭建一个ExtJS 4.2单页面应用, 这里先介绍主页的搭建,内容包括:主页结构说明.扩展功能等方面. 目录 1. 主页结构说明 2. 扩展功能 3. 在线演示 1. 主页结构说明 1.1 主 ...
- 【Web动画】SVG 线条动画入门
通常我们说的 Web 动画,包含了三大类. CSS3 动画 javascript 动画(canvas) html 动画(SVG) 个人认为 3 种动画各有优劣,实际应用中根据掌握情况作出取舍,本文讨论 ...
- zookeeper源码分析之五服务端(集群leader)处理请求流程
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
- 【NLP】Python NLTK处理原始文本
Python NLTK 处理原始文本 作者:白宁超 2016年11月8日22:45:44 摘要:NLTK是由宾夕法尼亚大学计算机和信息科学使用python语言实现的一种自然语言工具包,其收集的大量公开 ...
- 【定有惊喜】android程序员如何做自己的API接口?php与android的良好交互(附环境搭建),让前端数据动起来~
一.写在前面 web开发有前端和后端之分,其实android还是有前端和后端之分.android开发就相当于手机app的前端,一般都是php+android或者jsp+android开发.androi ...
- "NHibernate.Exceptions.GenericADOException: could not load an entity" 解决方案
今天,测试一个项目的时候,抛出了这个莫名其妙的异常,然后就开始了一天的调试之旅... 花了很长时间,没有从代码找出任何问题... 那么到底哪里出问题呢? 根据下面那段长长的错误日志: -- ::, ...
- APP多版本共存,服务端如何兼容?
做过APP产品的技术人员都知道,APP应用属于一种C/S架构的,所以在做多版本兼容,升级等处理则比较麻烦,不像web应用那么容易.下面将带大家分析几种常见的情况和应对方式: 小改动或者新加功能的 这种 ...
- [Hadoop in Action] 第7章 细则手册
向任务传递定制参数 获取任务待定的信息 生成多个输出 与关系数据库交互 让输出做全局排序 1.向任务传递作业定制的参数 在编写Mapper和Reducer时,通常会想让一些地方可以配 ...