NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

Flash 务实主义(七)——构建易维护的程序:高效修改

  • 2011-06-10
  • 本文字数:3156 字

    阅读完需:约 10 分钟

一般程序开发完成后就进入了繁琐无趣的后期维护阶段,请不要以为一个不停更新的项目后期维护是一件轻松的事情,它会暴露出开发过程中的所有硬伤,不规范的写法、混乱的逻辑结构、高耦合导致地牵一发而动全身。虽然开发内容实际上减少了,但人力成本反而更高。

要提高这方面效率有很多技巧,本文介绍的内容只是起点–如何快速找到项目中需要修改的代码。

一般出现问题首先看到得是表现部分,例如对话框,关系到一些具体逻辑或某个服务端请求,即使不是很清晰的部分也一定有临近的区域。根据表现找到其对应代码,我将其称为定位。

搜索关键字:泛用但低效

搜索关键字是广泛使用的方法。例如,你在节目上看到某个图片,找到图片标志,在所有代码中搜索图片标志,一定可以找到调用这个图片的代码。再如,屏幕中显示的文本,也能找到对应的语言包标识,找到相关代码。然而,这种做法效率很低,因为你要找到标识的具体拼写,搜索项目代码查找关键字也需要时间。所以下面主要介绍如何不借助搜索直接找到目标代码。

包结构

类一般可以从两个维度分类,一个维度是结构类别,如模型、视图、控制器,甚至工具类、组件,另外一个维度是业务类别,如商店、人物、战斗等各种不同模块。

目录里的文件只有一个根,类似单继承,所以你只能用一个分类做为大类别。一般情况都是用结构类别做为大类别,因为结构类别一般是固定不变地,而业务类别可能会经常变化。例如下图所示情况:

这样做是为了避免大量类混杂在一起,只有分到不同目录才能彻底解决这个问题 (目录可折叠,必要时子目录或文件命名可重复)。开发模块时,只需展开关心的目录,避免其他文件干扰。

文件命名

推荐文件名根据结构类别做前缀,如视图以 UI 开头、后台请求以 Rpc 开头等。如果没有前缀,命名时很容易遇到重复的情况。再以业务类型设定第二个前缀,使得没有目录时,按字母排序时同一系统中的类被排到一起,当然也可以防止重名。

恰当的命名会在利用代码提示引入类时提供便利,而且在打开类(ctrl+shift+T)对话框里也比较容易找到需要的类。当然,主要还是在查看包资源时,列表会比较整齐,方便找到特定文件。

以上是为了帮助你在知道类的功能和类别却不确定具体命名时使用的,你可能不记得具体名字,但应该可以判断出它所在的包,但仅仅这样是不够的。

逻辑分离是前提

逻辑要按一定规则分开到不同类中,否则你的查找目标本身就不存在。

MVC 是实现逻辑分离的方法之一。根据 MVC 思想将类分开,你就会很清楚知道,与用户交互、显示有关的类是在视图中,与数据格式转换、获取特定数据 (诸如获得图标实例)、判断 (诸如 isPropTask() 之类)、修改数据逻辑 (诸如修改经验值触发升级) 是在模型中,而制定特定服务器请求、设置模型数据、引起数个视图更新的代码一定是在服务器请求类的 result 中。这样就能确定目标位置,即使不能确定具体某个类,也能界定到某个包范围内。

当然这是需要事先约定的,但只要开发者理解并遵守这个约定,就可以做到不依赖搜索关键字也能立即找到需要修改的代码。毫无疑问这种做法是值得的。

从视图着手

视图是最容易找到的部分,然后根据交互事件模拟用户操作过程,通过调用关系一层层查找,最后就能找到需要的部分。

无论你的代码结构如何,这种方法都是通用可行的。如果你的目标就是视图,需要修改的是诸如布局、颜色、数据填充逻辑,这样做就可以了。但如果你的目标不是视图,这并不是最好的办法,因为毕竟需要从视图一层层中转,会多几个步骤而不是直接找到,这自然影响效率。

模型

模型不只是数据。

很多人不明白为什么要在数据之外套一层模型。代码放哪里比较好要以可复用性做为标准,放在模型里的逻辑应该是和数据密切交流的,最基本的是数据序列化和反序列化。这些内容不少人认为应该写在请求完成函数里,而实际应该写在模型中,因为同一个模型可能会由不同请求生成,它们传入的数据格式是一样的,只有在模型中解析才能重复利用这段功能代码。

此外模型还需要负责和数据相关的逻辑,以某个 RPG 游戏为例:

  • 人物属性变化:包括金钱变化(钱不够会失败并提示充值),经验变化(可能需要升级),还有数据更新后对应视图更新;
  • 道具管理:增加 / 删除道具,获得道具数量,判断道具满;
  • 计算:诸如保存地图模型可以提供计算 A* 的方法;

上述逻辑是针对游戏玩家的,只会存在一个模型,数据模型是固定的,所以无论放在哪里只要集中都容易查找,但显然放在模型里最好理解,而且这样即使出现多角色需求,需要修改的地方也很少。

模型通常也会提供一些简单的数据转换方法,例如:

  • 获得图标,类似的方法有获取格式化文本、获得 ToolTip 信息等;
  • 校验,一般一组条件的与 或关系或者大于 等于 小于判断,也可能有循环遍历数据进行统计等复杂表达式;

如果按照约定编码,将这些逻辑存放在模型中,这样就不能通过视图快速找到代码,但模型数量少、逻辑少,会比放在视图里找快很多。你也可以用查找引用方法找到调用模型方法的代码片段,以确定这个逻辑的入口,方便逆向追踪。这样只需修改一处,所有相关部分都会发生变化。

命令(Command/Action)

所谓命令,其实很大一部分都是用来请求服务端数据的,设计中有 result 方法可以在返回结果后处理一些事情,例如整理数据格式、设置模型、调用视图更新方法。虽然很多人将这些功能发明放在视图中,但显然放在 Command 里重用率更高且更易于定位。

服务端返回的数据会经常变换,虽然具体解析是在模型中完成,但返回的数据常常是多个数据拼凑在一起,可能是数组或者一些简单数据类型,这部分可以有 Command 处理,做特殊解析并给相关模型赋值。由于这部分需要与服务端沟通,是容易出错的地方,放在 Command 里容易找到,修改时也可以省去不少麻烦。

命令除了给模型赋值,也还会有一些触发操作。如果确定某个逻辑是请求返回一定执行的也可以放在这里。例如更新视图、触发附加逻辑、首次购买某物品的弹窗。这部分常发生变化,放在 Command 执行也易于调整。当然 Command 也可以与服务端请求无关,但道理是一样的。

总而言之,原则是尽可能不要将代码放在视图,而是放在联系更紧且数量少、代码少的一方,这样就能更快找到修改代码位置。Command 一般用来调用模型和视图方法,是其他逻辑的入口,自己只有少量代码。

常量类

配置类数据只可能存在于三个地方:服务端,本地配置文件,常量类。

对于服务端数据配置,客户端只单纯接受,本地配置文件一般都保持经常更新的大量数据,所以零散数据配置通常都存在常量类里,例如等级上限、各级经验分配、特定功能花费。

很多开发者都喜欢偷懒,例如一个功能需要花费 5 元开启,开发者直接在代码里写 5。这样看起来算不算神秘数字先不谈,要知道,这种数据即使说绝对不会变而它未来变化的几率也会超过 30%。所以常量是必须有的,哪怕数值是 1,也应该写成常量,因为未来可能变成 2,在代码里保留数字始终会有隐患。如果你设置为常量,对于这类内容就可以直接找到常量修改,而不用关心其他部分,也很容易找到使用这个常量的代码片段。如果没有常量的话,就只能借助和这个数值相关的内容引导并借助关键字搜索以确保修改无遗漏了。

此外,有多版本时配置可能会变化,如果硬编码写死在程序中,需求会很难实现。

其他

这里介绍是以通用 MVC 为例,因为熟悉的人较多,容易理解。游戏中除用户界面外,结构会更复杂,虽然也有类似模型视图这样的概念,但层次需要分得更细致。其实这些分离方法都是约定的,既然要分离,就要更合理、更易于理解、更具有可复用性。高效修改首先要容易找到问题症结点,要达到这个目的,就要求代码结构整理。良好的结构也可以让约定更加简洁,易于记忆和理解。

上述这些内容,框架并不能帮到你,因为框架大多是限制你分成几部分,而没有也无法限定这几部分具体是什么内容。因此你需要刻意地约定,而这个刻意地行为,对于减少修改维护时的人力成本,比框架重要百倍。

2011-06-10 18:381654

评论

发布
暂无评论
发现更多内容

明道云HAP合作伙伴计划全解析:开辟业务增长新路径

明道云

基于AB32VG1的冬笋探测器设计

智趣匠

lcd 微波

Macs Fan Control Pro for mac:智能风扇控制,优化散热,提升性能

Rose

短视频评论ID采集提取软件|评论关键词下载爬取工具

Geek_16d138

短视频获客 爬虫工具 爬虫技术

姑苏寻韵~庆开放原子开源大赛 OpenTiny 前端 Web 应用开发挑战赛路演圆满落幕。

OpenTiny社区

开源 前端 低代码 组件库

superbuy淘宝代购集运系统类似软件是哪家公司开发的?

tbapi

淘宝代购系统 superbuy

Proxifier for mac,让网络隐私与安全触手可及

Rose

支付系统概述(九):外汇系统

agnostic

支付系统设计与实现

机器狗巡视功能PRD

执于业务

使用PHP开发体育赛事直播平台,有这些缺点和优点

软件开发-梦幻运营部

Vue.js 如何在Vue应用中导入wasm文件

Changing Lin

Vue 前端

【实时更新】天猫商品详情数据接口采集揭秘!

tbapi

淘宝商品详情数据接口 天猫API接口 天猫商品详情接口 天猫商品数据采集

《JAVA多线程设计模式》PDF

程序员李木子

FeignClient从默认的httpClient升级为okhttpclient踩坑记录

追随月光的战士

k8s Wireshark Spring boot Feign 404

HAP官方示范应用大更新:开箱即用,全面整合新功能

明道云

安装plsql developer 64位

麦兜

关于Ingress-nginx的跨域配置

百度搜索:蓝易云

nginx Linux 运维 https HTTP

HagoBuy淘宝代购集运系统类似软件是哪家公司开发的?

tbapi

淘宝代购系统

华为Pura 70系列,一种关于世界之美的可能

脑极体

AI 手机

Vben-admin 修改Primary Color

麦兜

短视频批量下载提取软件功能|采集下载工具

Geek_16d138

短视频获客 爬虫工具

JProfiler for Mac v14.0.0永久注册码 Java性能调优利器

Rose

轻松驾驭大数据,IBM SPSS Statistics 26让统计分析更智能!

Rose

视频批量采集下载工具|短视频提取软件

Geek_16d138

短视频 爬虫工具 爬虫技术

国产化里程碑:明道云HAP私有部署版获信创评估证书,荣登会员单位

明道云

Python动态变量名定义与调用方法

百度搜索:蓝易云

Python 云计算 Linux 运维 云服务器

玛雅 maya2025 系统要求 及Autodesk Maya 2025完整版破解资源

Rose

鸿蒙HarmonyOS实战-ArkUI组件(Button)

蜀道山

鸿蒙 HarmonyOS 鸿蒙开发 button arkui

Pandabuy淘宝代购集运系统类似软件是哪家公司开发的?

tbapi

淘宝代购系统 淘宝代购集运系统 Pandabuy

route命令小结

百度搜索:蓝易云

Linux 运维 IP Route

Termius:全平台SSH神器,连接管理更高效!

Rose

Flash务实主义(七)——构建易维护的程序:高效修改_Java_flashyiyi_InfoQ精选文章