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

摘要:
每个View/ViewModel依赖其余对象,而本身又被其他View/ViewModel强引用。MVVM的核心思想就是解耦,View与ViewModel应该感受不到彼此的存在。交给中介者设计模式来解决吧。我们需要添加一个中介者,每个ViewModelPublisher对象都会在自己状态改变时,告诉中介者。它的Key为消息的唯一Id,Value代表一个对该Message的处理程序。但如果设计不当,中介者本身会变得过于复杂。

当你开发一个客户端应用程序的时候,往往一个单页会包含很多子模块,在不同的平台下,这些子模块又被叫成子View(视图),或者子Component(组件)。越是复杂的页面,被切割出来的子模块就越多,子模块越多,彼此之间需要同步的数据和状态就越频繁,即易产生耦合。那么如何保证在复杂业务情况下,各个子模块之间可以随意通信并保持弱耦合关系,这正是本文所讨论的。

耦合的产生

试想一下,你有这样一下需求,点击 View A中的按钮,View B也需要做出相应的改变。

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

这不是很简单吗。脑海里迅速出现两种解决方案:

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 都需要告诉中介者请求来时进行怎样的响应。

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

在没有中介者之前对象之间都需要彼此认识,互相引用,是一种强耦合关系。有了中介者之后,彻底解耦。

那么现在就需要定义一个中介者,称为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"));

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

小结###

中介者模式常常用来协调相关的GUI组件,可以让对象之间传递的消息变得简单。但如果设计不当,中介者本身会变得过于复杂。
源代码托管在Github上,点击此了解

免责声明:文章转载自《Unity应用架构设计(2)——使用中介者模式解耦ViewModel之间通信》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇java插入emoji表情报错跨域之options请求详解下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Unity3d—GUI能量条

1、打开Unity编辑器。2、在脚本文件夹中添加C#脚本,我的是添加了skill_01这个脚本。(要自己设置文件夹,方便管理,不然文件添乱不方便管理) 3、注意,脚本的名字一旦确定就不要去改动,因为一个脚本的名字就是一个类名,改动会容易出现程序的不正确。4、编写对应的脚本代码1 usingSystem.Collections; 2 usingSystem....

Unity中的半透明阴影

在Unity中渲染半透明阴影可以使用Unity提供的dither texture。在这之前,先考虑一般半透明物体的渲染流程: 设置render queue为Transparent,这样不透明的物体会先渲染,然后位于被不透明物体遮挡的透明物体就可以不必渲染,减少开销 设置render type为Transparent,便于一些replacement操作 设...

Unity 场景分页插件 World Streamer 支持无限大地图的解决方案(二)

Terrain Streaming 可以用WorldCreator创建Tile地形,然后用WorldStreamer实现分块地图。比如10000*10000(16平方公里) 的地形,需要1000*1000的100个地块。如果每次加载9个格子,那么同时载入的地块大小为3000*3000大小——比一次加载100000*10000要省掉 90%的数据——如果直接...

unity3D 2D游戏碰撞道具增加气血效果&受伤掉血效果

代码并不高效,仅以实现效果为目的. 被攻击时调用(需要传入HP预制件父级对象) 1 //受到伤害时,掉血 2 public void OnHurt(Transform HP) 3 { 4 print("触碰到了怪物..."); 5 //遍历父级对象 6 for (int i =...

小议WebRTC拥塞控制算法:GCC介绍

网络拥塞是基于IP协议的数据报交换网络中常见的一种网络传输问题,它对网络传输的质量有严重的影响,网络拥塞是导致网络吞吐降低,网络丢包等的主要原因之一,这些问题使得上层应用无法有效的利用网络带宽获得高质量的网络传输效果。特别是在通信领域,网络拥塞导致的丢包,延迟,抖动等问题,严重的影响了通信质量,如果不能很好的解决这些问题,一个通信产品就无法在现实环境中正常...

[Linux环境编程] TCP通信与多线程编程实现“多人在线聊天室”

[linux环境编程] TCP通信与多线程编程实现“多人在线聊天室” 一、基本概念1、TCP通信   TCP(Transmission Control Protocol)就是传输控制通讯协议,是TCP/IP体系结构中最主要的传输协议。其“三次握手”提供了可靠的传送,高可靠性保证了数据传输不会出现丢失与乱序,再加之TCP连接两端设有缓存用来临时存放双向通信的...