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上,点击此了解
转载于:https://www.cnblogs.com/OceanEyes/p/set_up_subview_and_subviewmodel_part2.html
Unity应用架构设计(4)——设计可复用的SubView和SubViewModel(Part 2)相关推荐
- 视频教程-Unity网络游戏架构设计-Unity3D
Unity网络游戏架构设计 网名:海洋,CSDN社区讲师,3D游戏引擎开发者,IT讲师,计算机图形学方向研究生,曾在浙江大学CAD&CG;国家重点实验室学习.从事IT行业15年,主导或参与了1 ...
- Unity应用架构设计(10)——绕不开的协程和多线程(Part 1)
阅读目录 是否需要多线程? 协程的内部原理 小结 在进入本章主题之前,我们必须要了解客户端应用程序都是单线程模型,即只有一个主线程(Main Thread),或者叫做UI线程,即所有的UI控件的创建和 ...
- 大数据架构选型与设计
大数据架构选型与设计 1.1 如何构建大数据平台? 1.1.1 数据库与ER建模 1.1.1.1 数据库(DataBase) 数据库是按照数据结构来组织.存储和管理数据的仓库,是一个长期存储在计算机内 ...
- Java架构II_C1 软件架构设计导论_3 软件架构的风格
田超凡 原创博文,严禁复制转载,仿冒必究,部分素材转载自慕课网 ...
- 软考·系统架构师论文——论基于架构的软件设计方法及应用
文章目录 说明 摘要 过渡 项目背景 论点理论+实践 结尾 说明 1.[摘要 300~330字] ① 项目介绍:时间.项目名.项目主要功能简述.作者角色及工作内容 ② 项目技术简介:正文理论/分论点的 ...
- java对象扩展方法_高可扩展的面向对象代码架构是如何设计的
导语 Java后端程序员的日常工作,大多数可能都是写基于数据库CRUD的Dao层.Manager层.Service层.Controller层,需求来了,就对着这几个层一顿怼代码.调试跑通了,就完事了. ...
- 架构设计——接口设计
开发中接口常用方式:前后端交互(Rest),系统交互(RPC)最普遍的一种方式. 接口文档详细,异常定义清晰 满足最小需求原则:尽可能的减少参数,更不允许添加无用的参数. 单一职责:接口粒度应该尽量小 ...
- 云原生应用程序的架构应该怎么设计?
介绍 云原生是一种将应用程序构建为微服务并在容器化和动态编排平台上进行运行的方法,这些平台充分利用了云计算模型的优势.云原生关注的是如何创建和部署应用程序,而不是在哪里运行.这些技术使组织能够在现代的 ...
- 三层架构:软件设计架构
三层架构:软件设计架构 1. 界面层(表示层):用户看的得界面.用户可以通过界面上的组件和服务器进行交互 2. 业务逻辑层:处理业务逻辑的. 3. 数据访问层:操作数据存储文件.
- 认证鉴权与API权限控制在微服务架构中的设计与实现
引言: 本文系<认证鉴权与API权限控制在微服务架构中的设计与实现>系列的第一篇,本系列预计四篇文章讲解微服务下的认证鉴权与API权限控制的实现. 1. 背景 最近在做权限相关服务的开发, ...
最新文章
- C# 算法系列一基本数据结构
- Js实现回车登录,监听回车事件
- centOS 6 rpm安装MySQL小记
- 阿里云SAG2.0发布,助力企业全球互联
- [Vue.js] 深入 -- 组件化开发
- PC电脑端社交应用设计灵感
- gog 中 git提交push到远程时出现error: RPC failed; HTTP 413 curl 22
- Win10企业版安装应用商店
- C语言每个语句的最后必须有一个分号,C语言选择题附答案
- 简洁易用的日志模块——log4j
- Eclipse使用大全
- 原生JS获取单选框或复选框的选中值的方法
- Linux之git用法
- Matlab读取shp文件及存储形式
- x3650 m5U盘安装Linux,x3650 m5 u盘安装win10u盘驱动修复失败怎么办
- 微信搜索刷关键词推广方法
- PYTHON学习笔记---函数
- linux操作系统:x86架构,一个良好的运营环境
- 【SharePoint】SharePoint 文档库中html文件打开后直接通过浏览器访问,而不是直接下载
- 利用 tkinter 写表白软件,加入动画效果