Unity 3D Framework Designing(2)——使用中介者模式解耦ViewModel之间通信
当你开发一个客户端应用程序的时候,往往一个单页会包含很多子模块,在不同的平台下,这些子模块又被叫成子View(视图),或者子Component(组件)。越是复杂的页面,被切割出来的子模块就越多,子模块越多,彼此之间需要同步的数据和状态就越频繁,即易产生耦合。那么如何保证在复杂业务情况下,各个子模块之间可以随意通信并保持弱耦合关系,这正是本文所讨论的。
耦合的产生
试想一下,你有这样一下需求,点击 View A中的按钮,View B也需要做出相应的改变。
这不是很简单吗。脑海里迅速出现两种解决方案:
1.View A 主动通知View B做出更新,也就是View A依赖 View B
void Notify()
{
ViewB.Update(color);
}
2.View B监听View A的ColorChanged事件,主动拉取数据并更新,即ViewB 依赖View A
ViewA.OnColorPropertyValueChanged+=(color)=>{
Update(color);**
}
这两种实现毫无疑问是没问题的,至少从结果上来看是正确的。但试想一下,在一个复杂的客户端单页应用程序,这种紧耦合关系会导致程序的复杂度陡然上升。每个View/ViewModel依赖其余对象,而本身又被其他View/ViewModel强引用。这显然不是好的实践方式。
还记得我在上一篇文章的对于MVVM的描述吗?
MVVM的核心思想就是解耦,View与ViewModel应该感受不到彼此的存在。ViewModel与ViewModel之间也应该感受不到彼此的存在。
中介者模式的引入
那么如何消除这种紧耦合关系呢?交给中介者设计模式来解决吧。
我们需要添加一个中介者,每个ViewModel Publisher对象都会在自己状态改变时,告诉中介者。每个ViewModel Subscribers 都需要告诉中介者请求来时进行怎样的响应。
在没有中介者之前对象之间都需要彼此认识,互相引用,是一种强耦合关系。有了中介者之后,彻底解耦。
那么现在就需要定义一个中介者,称为MessageAggregator。因为由它来转发消息,所以核心是一个字典,保存了所有需要被转发的消息。它的Key为消息的唯一Id,Value代表一个对该Message的处理程序。
public delegate void MessageHandler<T>(object sender, MessageArgs<T> args);
public class MessageAggregator<T>
{
private readonly Dictionary<string, MessageHandler<T>> _messages = new Dictionary<string, MessageHandler<T>>();
public static readonly MessageAggregator<T> Instance=new MessageAggregator<T>();
private MessageAggregator()
{
}
public void Subscribe(string name, MessageHandler<T> handler)
{
if (!_messages.ContainsKey(name))
{
_messages.Add(name, handler);
}
else
{
_messages[name] += handler;
}
}
public void Publish(string name, object sender, MessageArgs<T> args)
{
if (_messages.ContainsKey(name) && _messages[name] != null)
{
//转发
_messages[name](sender, args);
}
}
}
解耦ViewModel与ViewModel###
通过中介者MessageAggregator对象,ViewModelB Subscribe一个对消息来时的处理函数:
MessageAggregator<object>.Instance.Subscribe("ColorChanged",ToggleHandler);
ViewModel A在自己状态改变时,Pulish状态改变的消息给中介者:
MessageAggregator<object>.Instance.Publish("ColorChanged", this,new MessageArgs<object>("Red"));
小结###
中介者模式常常用来协调相关的GUI组件,可以让对象之间传递的消息变得简单。但如果设计不当,中介者本身会变得过于复杂。
源代码托管在Github上,点击此了解
Unity 3D Framework Designing(2)——使用中介者模式解耦ViewModel之间通信的更多相关文章
- Unity应用架构设计(2)——使用中介者模式解耦ViewModel之间通信
当你开发一个客户端应用程序的时候,往往一个单页会包含很多子模块,在不同的平台下,这些子模块又被叫成子View(视图),或者子Component(组件).越是复杂的页面,被切割出来的子模块就越多,子模块 ...
- Unity 3D Framework Designing(3)——构建View和ViewModel的生命周期
> 对于一个View而言,本质上是一个MonoBehaviour.它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等.这些是非常好的方法,可以让开发者 ...
- Unity 3D Framework Designing(1)—— MVVM 模式的设计和实施(Part 2)
MVVM回顾 经过上一篇文章的介绍,相信你对 MVVM的设计思想有所了解.MVVM的核心思想就是解耦,View与ViewModel应该感受不到彼此的存在.View只关心怎样渲染,而ViewModel只 ...
- Unity 3D Framework Designing(1)—— MVVM 模式的设计和实施(Part 1)
初识 MVVM 谈起 MVVM 设计模式,可能第一映像你会想到 WPF/Sliverlight,他们提供了的数据绑定(Data Binding),命令(Command)等功能,这让 MVVM 模式得到 ...
- Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 1)
『可复用』这个词相信大家都熟悉,通过『可复用』的组件,可以大大提高软件开发效率. 值得注意的事,当我们设计一个可复用的面向对象组件时,需要保证其独立性,也就是我们熟知的『高内聚,低耦合』原则. 组件化 ...
- Unity 3D Framework Designing(6)——设计动态数据集合ObservableList
什么是 『动态数据集合』 ?简而言之,就是当集合添加.删除项目或者重置时,能提供一种通知机制,告诉UI动态更新界面.有经验的程序员脑海里迸出的第一个词就是 ObservableCollection.没 ...
- Unity 3D Framework Designing(7)——IoC工厂理念先行
一谈到 『IoC』,有经验的程序员马上会联想到控制反转,将创建对象的责任反转给工厂.IoC是依赖注入 『DI』 的核心,大名鼎鼎的Spring框架就是一个非常卓越的的控制反转.依赖注入框架.遗憾的是, ...
- Unity 3D Framework Designing(9)——构建统一的 Repository
谈到 『Repository』 仓储模式,第一映像就是封装了对数据的访问和持久化.Repository 模式的理念核心是定义了一个规范,即接口『Interface』,在这个规范里面定义了访问以及持久化 ...
- Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 2)
在我们设计和开发应用程序时,经常要用到控件.比如开发一个客户端WinForm应用程序时,微软就为我们提供了若干控件,这些控件为我们提供了可被定制的属性和事件.属性可以更改它的外观,比如背景色,标题等, ...
随机推荐
- Struts1文件上传、单文件、多文件上传【Struts1】
将struts1文件上传的操作汇总了一下,包括单文件上传和多文件上传,内容如下,留作备忘: Struts2实现文件上传的文章(http://blog.csdn.net/itwit/article/d ...
- 循环语句——for语句
一.for语句结构:for (初始化表达式; 循环条件表达式 ;循环后的操作表达式 ) { 执行语句: } 循环条件表达式,必须是true或false 示例: class ForDemo { publ ...
- .bat文件设置IP、DNS
这几天遇到个烦心事,每次开机之后都要去手动去设置一下IP地址,一大串的数字还是有点麻烦,于是就想写个批处理文件设置IP 注意:在DOS下设置IP时需要管理员权限运行 1.查看机子设置IP需要用到的名字 ...
- gevent拾遗
在前文已经介绍过了gevent的调度流程,本文介绍gevent一些重要的模块,包括Timeout,Event\AsynResult, Semphore, socket patch,这些模块都涉及当 ...
- 覆写hashCode equal方法
1.为什么要重写hashCode方法? 当自己要新建一个class,并要把这个类放到HashMap的时候,需要覆写这两个办法.如果不覆写,放入两个新的对象,可能会是不相等的. 在java的集合中,判断 ...
- php上线教程----阿里云下设值二级域名并将项目上线
在工作中,我们需要在一个主机地址下分配多个域名来上线多个项目,但是怎么设置一个二级域名并且完成上线项目的,接下来我们就以阿里云为例演示整个上线流程 首先登陆你的阿里云,找到你的域名 点击解析,进入解析 ...
- 配置IIS Express以便通过IP地址访问调试的网站
问题背景 最近使用C#编写了一个WebService,希望通过Java进行调用.使用Visual Studio 2013调试WebService时,可以在浏览器中通过localhost地址访问WSDL ...
- [Linux] PHP程序员玩转Linux系列-备份还原MySQL
1.PHP程序员玩转Linux系列-怎么安装使用CentOS 2.PHP程序员玩转Linux系列-lnmp环境的搭建 3.PHP程序员玩转Linux系列-搭建FTP代码开发环境 前几天有个新闻,说是g ...
- 在 Windows 上测试 Redis Cluster的集群填坑笔记
redis 集群实现的原理请参考http://www.tuicool.com/articles/VvIZje 集群环境至少需要3个节点.推荐使用6个节点配置,即3个主节点,3个从节点. 新 ...
- 整理 - .Net系统预定义的委托们
大部分情况下,我们可以使用系统预定义的委托类型,而不需要自己再来手动定义. 以下委托都位于System命名空间下. 传入参数.返回值的类型,大都被声明为泛型. 1.Action系列 有0-16个参数, ...