当你开发一个客户端应用程序的时候,往往一个单页会包含很多子模块,在不同的平台下,这些子模块又被叫成子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应用架构设计(2)——使用中介者模式解耦ViewModel之间通信的更多相关文章

  1. Unity 3D Framework Designing(2)——使用中介者模式解耦ViewModel之间通信

    当你开发一个客户端应用程序的时候,往往一个单页会包含很多子模块,在不同的平台下,这些子模块又被叫成子View(视图),或者子Component(组件).越是复杂的页面,被切割出来的子模块就越多,子模块 ...

  2. Unity应用架构设计(1)—— MVVM 模式的设计和实施(Part 2)

    MVVM回顾 经过上一篇文章的介绍,相信你对MVVM的设计思想有所了解.MVVM的核心思想就是解耦,View与ViewModel应该感受不到彼此的存在. View只关心怎样渲染,而ViewModel只 ...

  3. Unity应用架构设计(11)——一个网络层的构建

    对于客户端应用程序,免不了和远程服务打交道.设计一个良好的『服务层』能帮我们规范和分离业务代码,提高生产效率.服务层最核心的模块一定是怎样发送请求,虽然Mono提供了很多C#网络请求类,诸如WebCl ...

  4. Unity应用架构设计(13)——日志组件的实施

    对于应用程序而言,日志是非常重要的功能,通过日志,我们可以跟踪应用程序的数据状态,记录Crash的日志可以帮助我们分析应用程序崩溃的原因,我们甚至可以通过日志来进行性能的监控.总之,日志的好处很多,特 ...

  5. Unity应用架构设计(9)——构建统一的 Repository

    谈到 『Repository』 仓储模式,第一映像就是封装了对数据的访问和持久化.Repository 模式的理念核心是定义了一个规范,即接口『Interface』,在这个规范里面定义了访问以及持久化 ...

  6. Unity应用架构设计(6)——设计动态数据集合ObservableList

    什么是 『动态数据集合』 ?简而言之,就是当集合添加.删除项目或者重置时,能提供一种通知机制,告诉UI动态更新界面.有经验的程序员脑海里迸出的第一个词就是 ObservableCollection.没 ...

  7. Unity应用架构设计(4)——设计可复用的SubView和SubViewModel(Part 1)

    『可复用』这个词相信大家都熟悉,通过『可复用』的组件,可以大大提高软件开发效率. 值得注意的事,当我们设计一个可复用的面向对象组件时,需要保证其独立性,也就是我们熟知的『高内聚,低耦合』原则. 组件化 ...

  8. Unity应用架构设计(1)—— MVVM 模式的设计和实施(Part 1)

    初识 MVVM 谈起 MVVM 设计模式,可能第一映像你会想到 WPF/Sliverlight,他们提供了的数据绑定(Data Binding),命令(Command)等功能,这让 MVVM 模式得到 ...

  9. Unity应用架构设计(10)————绕不开的协程和多线程(Part 1)

    在进入本章主题之前,我们必须要了解客户端应用程序都是单线程模型,即只有一个主线程(Main Thread),或者叫做UI线程,即所有的UI控件的创建和操作都是在主线程上完成的.而服务器端应用程序,也就 ...

随机推荐

  1. Get与Post方法的区别

    Http协议定义了很多与服务器交互的方法,最基本的有4种,分别是GET,POST,PUT,DELETE. 一个URL地址用于描述一个网络上的资源,而HTTP中的GET, POST, PUT, DELE ...

  2. jupyter notebook不能选择虚拟环境的解决方法

    今天使用dlib没有py37版本,因此创建了Version_36虚拟环境.但jupyter notebook默认的内核找不到新建的虚拟环境,解决方法是需要安装两个包: × ipykernel × nb ...

  3. 在ArchLinux中安装MySQL

    最近前端学习用到数据库的知识.鉴于MySQL被甲骨文收购的情况,我从MariaDB开始学习.操作系统Manjaro 17.1, 数据库版本MariaDB 10.1. 1. 安装MariaDb和其客户端 ...

  4. Windows 7 下如何配置 java 环境变量

    安装 JDK.从Oracel官方网站上下载,下载完成后安装. http://www.oracle.com/technetwork/java/javase/downloads/jdk8-download ...

  5. GBT 31000-2015 社会治安综合治理基础数据规范 数据项 编码

    动态掌握 各级 综治组织 和 队伍建设 情况. 对 综治组织建设和其他业务 进行 统计. -- 数据描述 包括 序号  数据项名称 数据项类型 数据项长度 是否必填 相关条文和标准 -- 综治机构 包 ...

  6. [Python]mysql-python 安装错误 fatal error C1083: Cannot open include file: 'config-win.h': No such file or directory

    需要安装mysql connector 前往 https://dev.mysql.com/downloads/connector/python/ 下载 选择Platform independence, ...

  7. BZOJ.1812.[IOI2005]Riv 河流(树形背包)

    BZOJ 洛谷 这个数据范围..考虑暴力一些把各种信息都记下来.不妨直接令\(f[i][j][k][0/1]\)表示当前为点\(i\),离\(i\)最近的建了伐木场的\(i\)的祖先为\(j\),\( ...

  8. Linux服务部署--Java(一)

    网络配置 一.配置dns 1.修改/etc/NetworkManager/NetworkManager.conf 文件,在main部分添加 “dns=none” 选项: 2.NetworkManage ...

  9. python基础一 ------可迭代类型的连接

    对可迭代迭代进行连接,返回一个可迭代对象 两种方式: 并行连接 zip() 串行连接 itertools.chain from itertools import chain #并行连接 print(& ...

  10. React Native升级目标SDK

    React Native升级目标SDK 打开在 android/app/的build.gradle 找到 android { } 区块 改变以下属性 compileSdkVersion 26 buil ...