Unity应用架构设计(4)——设计可复用的SubView和SubViewModel(Part 2)
在我们设计和开发应用程序时,经常要用到控件。比如开发一个客户端WinForm应用程序时,微软就为我们提供了若干控件,这些控件为我们提供了可被定制的属性和事件。属性可以更改它的外观,比如背景色,标题等,而事件可以丰富控件的行为,比如最常见的『按钮点击』,谁也不能确定点击之后将发生什么事,是连接数据库呢还是弹出警告框,在不同的场景下,『按钮点击』 的行为往往呈现不一致。所以,与其举棋不定,还不如把处理委托给开发者,这就是『OnClick』事件。
SubView行为多变性
在上篇文章中,我阐述了为什么要使用SubView,总结起来就3个字:『可复用』 。那么问题来了,既然是可复用,那就意味着SubView可以在任何场景下使用,那怎样才能确保它做的是正确的行为呢?
举个栗子,还是 以如下图FaceBox为例,不同的场景下点击头像应该处理不同的事:

- 在战团中点击头像,则显示该成员的具体信息
- 在队伍里点击头像,则进入换人界面
- 在战斗时点击头像,则显示它配置的战术
你看,同样一个SubView,在不同的场景下它的行为往往是不一致的。那我们怎么去跟踪这些行为呢?
定制SubView的行为
你可能会以如下方式去定制SubView的行为:
void OnClick(){
if(战团){
显示该成员的具体信息
}else if(队伍){
进入换人界面
}else if(战斗){
显示它配置的战术
}else{
//其他
}
}
还是那句话这样,这样并没有错,甚至对某些SubView而言逻辑还很清晰。但仔细想想,这是最好的实践吗?
- 如果我要继续添加一种情况,是不是只能在else if扩展,违反了开闭原则,应该对扩展是开放的,对修改是关闭的
- 既然这个SubView是可复用的,那意味着将它放在任何项目中都是没问题的,但实际上OnClick里面处理了业务逻辑,紧耦合当前游戏的业务
所以显然上述代码不是最佳实践。那我们应该怎样去解决呢?
实际从开头的引言我已经提出了解决方案,以事件的形式委托给开发者来确定。一个Button也好,还是一个SubView也好,他们都是可复用的组件,不应该与具体的业务逻辑相结合。通过事件或者委托的形式,暴露给开发者来决定究竟要处理什么逻辑,这样才能和具体业务逻辑解耦。
委托的介入
还是以FaceBox举例,那么从上面的分析得出结论,我们需要定义委托或者事件,那应该定义在FaceBoxView呢还是FaceBoxViewModel中呢?
还是那句话,View不处理具体的业务逻辑,View将请求交给ViewModel去处理。
故在FaceBoxViewModel中增加可被外界监听的委托或者事件,我以委托举例,实际上事件就是特殊的委托。
public class FaceBoxViewModel:ViewModelBase
{
//省略部分代码
public delegate void OnBeginDragHandler();
public OnBeginDragHandler OnBeginDrag;
public delegate void OnDragHandler();
public OnDragHandler OnDrag;
public delegate void OnEndDragHandler();
public OnEndDragHandler OnEndDrag;
public delegate void OnClickHandler();
public OnClickHandler OnClick;
//省略部分代码
}
FaceBoxView不处理具体的逻辑,交由FaceBoxViewModel去实现:
protected override void OnInitialize()
{
//省略部分代码
//监听事件
var beginDragEntry = new EventTrigger.Entry();
beginDragEntry.eventID = EventTriggerType.BeginDrag;
beginDragEntry.callback.AddListener(eventData => { OnBeginDrag(); });
eventTrigger.triggers.Add(beginDragEntry);
var dragEntry = new EventTrigger.Entry();
dragEntry.eventID = EventTriggerType.Drag;
dragEntry.callback.AddListener(eventData => { OnDrag(); });
eventTrigger.triggers.Add(dragEntry);
var endDragEntry = new EventTrigger.Entry();
endDragEntry.eventID = EventTriggerType.EndDrag;
endDragEntry.callback.AddListener(eventData => { OnEndDrag(); });
eventTrigger.triggers.Add(endDragEntry);
var pointClickEntry = new EventTrigger.Entry();
pointClickEntry.eventID = EventTriggerType.PointerClick;
pointClickEntry.callback.AddListener(eventData => { OnClick(); });
eventTrigger.triggers.Add(pointClickEntry);
}
private void OnClick()
{
if (BindingContext.OnClick != null)
{
BindingContext.OnClick();
}
}
脑海里梳理一下请求的流程:FaceBoxView.PointClick->FaceBoxViewModel.OnClick()->委托给外部的某个Handler。
小结
实际上『委托』这个概念非常重要,和具体的语言、平台无关。比如在iOS开发经常听到代理模式,顾名思义,将请求交给具体的处理者去处理。设计模式并不深奥,很多模式的理念都是相通的,不同的是对应语言下不同的表现形态,善于剖开现象看本质,很多都是相通的。
源代码托管在Github上,点击此了解
Unity应用架构设计(4)——设计可复用的SubView和SubViewModel(Part 2)的更多相关文章
- Unity应用架构设计(4)——设计可复用的SubView和SubViewModel(Part 1)
『可复用』这个词相信大家都熟悉,通过『可复用』的组件,可以大大提高软件开发效率. 值得注意的事,当我们设计一个可复用的面向对象组件时,需要保证其独立性,也就是我们熟知的『高内聚,低耦合』原则. 组件化 ...
- Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 1)
『可复用』这个词相信大家都熟悉,通过『可复用』的组件,可以大大提高软件开发效率. 值得注意的事,当我们设计一个可复用的面向对象组件时,需要保证其独立性,也就是我们熟知的『高内聚,低耦合』原则. 组件化 ...
- Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 2)
在我们设计和开发应用程序时,经常要用到控件.比如开发一个客户端WinForm应用程序时,微软就为我们提供了若干控件,这些控件为我们提供了可被定制的属性和事件.属性可以更改它的外观,比如背景色,标题等, ...
- 认证鉴权与API权限控制在微服务架构中的设计与实现(四)
引言: 本文系<认证鉴权与API权限控制在微服务架构中的设计与实现>系列的完结篇,前面三篇已经将认证鉴权与API权限控制的流程和主要细节讲解完.本文比较长,对这个系列进行收尾,主要内容包括 ...
- atitit.系统架构图 的设计 与工具 attilax总结
atitit.系统架构图 的设计 与工具 attilax总结 1. 架构图的4个版式(标准,(左右)悬挂1 2. 架构图的层次结构(下属,同事,助手)1 3. wps ppt1 4. 使用EDraw画 ...
- Java生鲜电商平台-App系统架构开发与设计
Java生鲜电商平台-App系统架构开发与设计 说明:阅读此文,你可以学习到以下的技术分享 1.Java生鲜电商平台-App架构设计经验谈:接口的设计2.Java生鲜电商平台-App架构设计经验谈:技 ...
- Java生鲜电商平台-商品基础业务架构设计-商品设计
Java生鲜电商平台-商品基础业务架构设计-商品设计 在生鲜电商的商品中心,在电子商务公司一般是后台管理商品的地方.在前端而言,是商家为了展示商品信息给用户的地方,它是承担了商品的数据,订单,营销活动 ...
- zz《分布式服务架构 原理、设计与实战》综合
这书以分布式微服务系统为主线,讲解了微服务架构设计.分布式一致性.性能优化等内容,并介绍了与微服务系统紧密联系的日志系统.全局调用链.容器化等. 还是一样,每一章摘抄一些自己觉得有用的内容,归纳整理, ...
- ABSD 基于架构的软件设计方法方法简介(摘抄)
ABSD(Architecture-Based Software Design)基于架构的软件设计方法 有三个基础: 第一个基础是功能分解.在功能分解中,ABSD方法使用已有的基于模块的内聚和耦合技术 ...
随机推荐
- iframe实现伪ajax
iframe实现伪ajax 数据提交的两种方式: Form Ajax Ajax提交数据的方法: JS实现 Jquery “伪”Ajax "伪"Ajax: iframe+from实现 ...
- PostgreSQL 的命令行工具 psql 的常用命令
1. 连接服务器: psql -h 192.168.1.88 -U username -d databasename 2. 切换数据库: \c dbname 3. 列出所有数据库: \l 4. 列出所 ...
- 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-6 直接光源采样
Chapter7 Sample Lights Directly Preface 今天我们来讲这个还算牛逼的技术——直接光源采样 之前我们提到过,在2-7 前两篇我们也提到要减少噪点,就是图片上的黑点 ...
- this 相关(2)
this 的指向与所在方法的调用位置有关,而与方法的声明位置无关 var obj = { val: 1, getVal: function() { console.log(this.val); } } ...
- 2018ddctf wp
杂项 第一题:颜文字 看过以后开始没思路:后来有师傅说是十六进制 我就上网百度了一下http://tieba.baidu.com/p/3717777553 但是不可能是完全十六进制啊,毕竟出题人很羞涩 ...
- ContextRefreshedEvent事件使用注意事项(Spring)
0 概述ContextRefreshedEvent 事件会在Spring容器初始化完成会触发该事件.我们在实际工作也可以能会监听该事件去做一些事情,但是有时候使用不当也会带来一些问题. 1 防止重复触 ...
- AE模板
== 蓝色浩瀚星辰中一道光速展示企业LOGO AE模板 科技公司品牌开场动画. == 线条科技感图片商品介绍 Tech Grid Show免费下载 科技科幻风格. 产品介绍不错. == 炫光三维金属质 ...
- Nowcoder牛客网NOIP赛前集训营-提高组(第六场)
A 拓扑排序+倍增哈希 或者 拓扑排序对于每个点计一个rank,每个点优先选取rank靠前的最小边权点 每次依然按照rank排序更新rank #include<bits/stdc++.h> ...
- 51Nod.1766.树上最远点对(树的直径 RMQ 线段树/ST表)
题目链接 \(Description\) 给定一棵树.每次询问给定\(a\sim b,c\sim d\)两个下标区间,从这两个区间中各取一个点,使得这两个点距离最远.输出最远距离. \(n,q\leq ...
- 潭州课堂25班:Ph201805201 django 项目 第二十六课 docker简介 (课堂笔记)
官方文档: https://docs.docker.com/install/linux/docker-ce/ubuntu/#set-up-the-repository 1,更新下sudo apt-ge ...