Unity 3D Framework Designing(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 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 2)的更多相关文章
- Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 1)
『可复用』这个词相信大家都熟悉,通过『可复用』的组件,可以大大提高软件开发效率. 值得注意的事,当我们设计一个可复用的面向对象组件时,需要保证其独立性,也就是我们熟知的『高内聚,低耦合』原则. 组件化 ...
- Unity 3D Framework Designing(6)——设计动态数据集合ObservableList
什么是 『动态数据集合』 ?简而言之,就是当集合添加.删除项目或者重置时,能提供一种通知机制,告诉UI动态更新界面.有经验的程序员脑海里迸出的第一个词就是 ObservableCollection.没 ...
- 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(7)——IoC工厂理念先行
一谈到 『IoC』,有经验的程序员马上会联想到控制反转,将创建对象的责任反转给工厂.IoC是依赖注入 『DI』 的核心,大名鼎鼎的Spring框架就是一个非常卓越的的控制反转.依赖注入框架.遗憾的是, ...
- Unity 3D Framework Designing(9)——构建统一的 Repository
谈到 『Repository』 仓储模式,第一映像就是封装了对数据的访问和持久化.Repository 模式的理念核心是定义了一个规范,即接口『Interface』,在这个规范里面定义了访问以及持久化 ...
- Unity应用架构设计(4)——设计可复用的SubView和SubViewModel(Part 1)
『可复用』这个词相信大家都熟悉,通过『可复用』的组件,可以大大提高软件开发效率. 值得注意的事,当我们设计一个可复用的面向对象组件时,需要保证其独立性,也就是我们熟知的『高内聚,低耦合』原则. 组件化 ...
- Unity 3D Framework Designing(2)——使用中介者模式解耦ViewModel之间通信
当你开发一个客户端应用程序的时候,往往一个单页会包含很多子模块,在不同的平台下,这些子模块又被叫成子View(视图),或者子Component(组件).越是复杂的页面,被切割出来的子模块就越多,子模块 ...
随机推荐
- this的相关介绍与用法
当一个对象创建后,Java虚拟机(JVM)就会给这个对象分配一个引用自身的指针,这个指针的名字就是this.因此,this只能在类中的非静态方法中使用,静态方法和静态的代码块中绝对不能出现this,并 ...
- iOS Touch ID 身份认证
iOS Touch ID 身份认证 iOS 8 及以后录了指纹的设备可以使用 touch ID 进行身份认证,指纹符合录入的指纹才能认证成功. 步骤 导入 LocalAuthentication 框架 ...
- 设置npm安装模块目录<nodejs>
nodejs安装模块命令: npm install <input_name> # 本地安装 npm install <input_name> -g # 全局安装 1.npm i ...
- 【前端】:JavaScript
前言: 开始学JavaScript,Dom,jQuery了,知识好杂,本身记忆力就不行的~~这篇博客简单介绍下JavaScript. 下篇博客写关于Dom的. JavaScript是一门编程语言(之前 ...
- js设计模式--单体模式
GOF里的23种设计模式, 也是在软件开发中早就存在并反复使用的模式. 如果程序员没有明确意识到他使用过某些模式, 那么下次他也许会错过更合适的设计 (这段话来自<松本行弘的程序世界>). ...
- java初级开发程序员(第六单元)
1.for循环结构: 循环结构分为四个部分. >初始部分:设置循环的初始状态,如设置记录循环次数的变量i为0. >循环体:重复执行的代码,即输出“好好学习,天天向上!”. >迭代部分 ...
- OpenCv 2.4.9 (二) 核心函数
前言 经过前面一节的怎样读取图片,我们可以做一些有趣的图像变换,下面我们首先介绍使用遍历的方法实现,然后我们使用内置的函数实现. 矩阵掩码实现 矩阵掩码,和卷积神经网络中的卷积类似.一个例子如下: 现 ...
- 在Windows平台搭建轻巧的Python开发环境——面向工程和科研的扩展包配置
首先,下载最新版本的Python. 为什么强调最新版本呢,因为新版本的漏洞通常会少得多,而且反映了未来的趋势. 既然要学,何不起点高一点? 官方下载地址:https://www.python.org/ ...
- Jquery的学习:基础核心!
一.什么是 jQuery jQuery是一个JavaScript库,它通过封装原生的JavaScript函数得到一整套定义好的方法.它的作者是John Resig,于2006年创建的一个开源项目,随着 ...
- [PKU2389]Bull Math (大数运算)
Description Bulls are so much better at math than the cows. They can multiply huge integers together ...