当你开发一个客户端应用程序的时候,往往一个单页会包含很多子模块,在不同的平台下,这些子模块又被叫成子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之间通信的更多相关文章

  1. Unity应用架构设计(2)——使用中介者模式解耦ViewModel之间通信

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

  2. Unity 3D Framework Designing(3)——构建View和ViewModel的生命周期

    > 对于一个View而言,本质上是一个MonoBehaviour.它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等.这些是非常好的方法,可以让开发者 ...

  3. Unity 3D Framework Designing(1)—— MVVM 模式的设计和实施(Part 2)

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

  4. Unity 3D Framework Designing(1)—— MVVM 模式的设计和实施(Part 1)

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

  5. Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 1)

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

  6. Unity 3D Framework Designing(6)——设计动态数据集合ObservableList

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

  7. Unity 3D Framework Designing(7)——IoC工厂理念先行

    一谈到 『IoC』,有经验的程序员马上会联想到控制反转,将创建对象的责任反转给工厂.IoC是依赖注入 『DI』 的核心,大名鼎鼎的Spring框架就是一个非常卓越的的控制反转.依赖注入框架.遗憾的是, ...

  8. Unity 3D Framework Designing(9)——构建统一的 Repository

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

  9. Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 2)

    在我们设计和开发应用程序时,经常要用到控件.比如开发一个客户端WinForm应用程序时,微软就为我们提供了若干控件,这些控件为我们提供了可被定制的属性和事件.属性可以更改它的外观,比如背景色,标题等, ...

随机推荐

  1. FindPkgConfig----CMake的pkg-config模块

    FindPkgConfig A pkg-config module for CMake. CMake的pkg-config模块. Finds the pkg-config executable and ...

  2. php连接 mysql 数据库

    php 连接数据库 一般是用面向对象的方法,需要先创建一个对象,即造一个连接对象,然后再写sql语句,(增改查删),最后执行sql语句 其中在创建连接对象时 我们用到的是MySQLI  是不区分大小写 ...

  3. JS打开摄像头并截图上传

    直入正题,JS打开摄像头并截图上传至后端的一个完整步骤 1. 打开摄像头主要用到getUserMedia方法,然后将获取到的媒体流置入video标签 2. 截取图片主要用到canvas绘图,使用dra ...

  4. Odd Numbers of Divisors

    给出一个正奇数K,两个正整数low,high. 有多少整数属于[low, high],且包含K个因子. 数据 C(0 < C < 1e5),测试样例数. (1 < K < 10 ...

  5. IOS编程学习笔记

    @interface -实例对象 +类名 #import "MyClass" @implementation MyClass -(id)initWithString:(NSStri ...

  6. 创建Win32图形界面应用程序

    没有什么比创建一个Win32图形界面应用程序能让Win32汇编初学者更兴奋的了! 然而,对于像我这样没有代码便会陷入困境的人来说,看到下面的代码总能让人为之一振,百余行的代码使得Win32GUI编程并 ...

  7. jQuery基本知识

    jquery基本操作笔记   jq和js 可以共存,不能混用: 1 2 3 4 5 6 $('.box').css('background','red'); $(".box").c ...

  8. axios全攻略

    随着 vuejs 作者尤雨溪发布消息,不再继续维护vue-resource,并推荐大家使用 axios 开始,axios 被越来越多的人所了解.本来想在网上找找详细攻略,突然发现,axios 的官方文 ...

  9. php中的实用分页类

    <table width="100%" border="1" cellpadding="0" cellspacing="0& ...

  10. Android 退出多Activity的application的方式

    在开发过程中,我们常常需要一个退出功能,来退出该应用的所有Activity.下面,我们列举一些退出应用的几种方式.以下用的源码点击查看源码地址 欢迎star,欢迎fork 利用ActivityCont ...