对Android和iOS项目中的模块结构和类结构设计的探讨
- 现有的代码规范缺少探讨的部分
1.1 关于项目的代码结构
通常来说,一个项目由多个模块组成;一个模块由多个类组成;一个类由多个方法组成;一个方法由多条语句组成;
按照代码粒度从大到小,可以划分为三个级别,并且分别对应IDE(XCode、Android Studio)的三个不同的视图:
- 项目结构,包括模块和类的组织——红框视图;
- 类结构,包括属性和方法的组织——绿框视图;
- 方法结构,包括变量和语句的组织——蓝框视图;
Xcode的三种视图(如下图)
Android Studio的三种试图(如下图)
1.2 关于现有代码规范
对于Android和iOS的现有代码规范,有大量的公司和大神进行了细致的探讨。其中,最有影响力的,笔者认为是苹果爸爸和阿里妈妈的两个版本——《Introduction to Coding Guidelines for Cocoa》、《阿里巴巴Android开发手册》。强烈推荐大家进行学习。
1.3 本文探讨的代码规范
但笔者发现,大部分现有的代码规范,讨论的主题都是命名规范、书写格式要求、特定技术点的处理要求等内容,关注点都是项目中具体代码细节,也就是蓝框部分的内容。但对于更大粒度的红框和绿框部分,也就是项目中模块和类的组织以及对类中方法的组织,讨论的并不多。
而在实际工作中,一位新员工加入公司,当然必须先学习公司的代码规范,明晰代码编写时需要注意的事项。然而,新员工加入实际项目后,首先看的其实并不是代码细节,而是项目代码的组织架构。一个具有良好组织结构的项目代码,可以让新员工在不看代码细节的前提下,直接了解项目的整体架构。
本文介绍的内容,就是通过对红框和绿框部分的设计,来探讨如何搭建一个“具有良好组织结构的项目”。
- 模块结构设计的探讨
一个好的项目结构,应该对模块和类的组织进行设计,实现不看实现细节,能够大概了解 项目功能 和 类功能;以下,分别使用Android和iOS两个例子进行说明。
背景介绍
本文举例的项目源码在这两个GitHub项目上:polyv-ios-cloudClass-sdk-demo、 polyv-android-cloudClass-sdk-demo
Demo项目是一个直播项目,包括两个页面,第一个是登录页,第二个是观看页。运行项目,会先进入登录页,登录成功后,会进入观看页。
2.1 iOS的例子
好的项目结构(如下图)
不好的项目结构(如下图)
好的项目结构,能够不看具体代码,而是能够 随着项目结构的逐层展开 直接获取到如下信息:
在项目中,有 Login(登录)和 Watch(观看)两个模块;
在 Login 模块 的主页面是 PLVLoginViewController(登录页);
在 Watch 模块 的页面包括 PLVLiveViewController(直播观看页) 和 PLVVodViewController(点播观看页);
在 Watch 模块有两个子模块,分别是 Media(视频区)和Charroom(聊天室);
在 Media(视频区)模块中,看到有三种 MediaViewController;看命名差异,可以发现是有两个维度划分的,分别是 Normal / PPT 、Live / Vod ;
在 Base 文件夹中,看到 PLVBaseMediaViewController ,猜测是三种 MediaViewController 的父类;
在 Base 文件夹中,看到 PPT 和 Live 两个文件夹,结合其中的 PLVBaseMediaViewController+PPT 和 PLVBaseMediaViewController+Live 两个catagory,可以猜测是在 父类 PLVBaseMediaViewController 的基础上增加 PPT 和 Live 两个维度的功能扩展;
一些建议
把 功能模块所使用的resource 放在 功能模块目录 下,是一个好的处理;
2.2 Android的例子
好的项目结构(如下图)
不好的项目结构(如下图)
好的项目结构,能够不看具体代码,而是能够 随着项目结构的逐层展开 直接获取到如下信息:
在项目中,有 Login(登录)和 Watch(观看)两个模块;
在 Login(登录)模块中,有一个 PolyvCloudClassLoginActivity 页面;
在 Watch(观看)模块中,有一个 PolyvCloudClassHomeActivity 页面;
在 Watch(观看)模块 有四个 子模块,chat(聊天室)、danmu(弹幕)、linkMic(连麦)、player(播放器);
在 chat(聊天室)模块中,可以猜测 PolyvChatBaseFragment 是父类Fragment,PolyvChatGroupFragment、PolyvChatPrivateFragment 是两个子类Fragment;而看到 PolyvChatFragmentAdapter ,可以猜测两个子类 Fragment 组成了一个 tab 显示样式;
在 chat(聊天室)模块中,看到 adapter 和 imageScan 目录;
在 adapter 目录中,看到两个 Adapter,猜测在 Fragment 中会有对应的两个列表(ListView 或者 RecyclerView);
在 imageScan 目录中,看到有 Fragment、View、PageAdapter,猜测是一个相对独立的完整功能;
一些建议
如果一个模块除了代码,还包括资源文件,那么,把代码和资源文件单独抽离为一个library库(比如上图中的commonui库),是一个比较好的处理,能和模块意外的代码、资源形成隔离;
- 类结构设计的讨论
一个好的项目结构,应该对方法的组织进行设计,通过对具体方法进行归类,实现不看实现细节,能够大概了解 类实现了哪些功能;以下,分别使用Android和iOS两个例子进行说明。
3.1 iOS的例子
好的类结构(如下图)
不好的类结构(如下图)
好的类结构,必须是根据功能进行分块的,每个方法从属于某一个功能分块中;
通过分块,可以不看具体方法的代码,直接了解到当前类涉及的功能;
其中有几个需要注意的要点:
常用的块有: life cycle(生命周期)、init(初始化)、IBAction(Action方法)、getter/setter(属性相关)、guesture(手势相关)、notification(通知相关)、net request(网络请求)、present viewcontroller(页面跳转)、单个delegate的实现
life cycle(生命周期) 分块中,方法应该按照 实际声明周期的执行顺序 进行排列;
(建议)IBAction分块中的方法,建议全部用Action作为后缀;
(建议).m 文件里方法的组织,要和 .h 文件里方法的声明 相对应
3.2 Android的例子
好的类结构(如下图)
不好的类结构(如下图)
好的类结构,必须是根据功能进行分块的,每个方法从属于某一个功能分块中;
通过分块,可以不看具体方法的代码,直接了解到当前类涉及的功能;
其中有几个需要注意的要点:
常用的块有: life cycle(生命周期)、init(初始化)、onClick(onClick方法)、onActivityResult(页面返回)、onRequestPermissionsResult(系统权限)、net request(网络请求)、start Activity(页面跳转)、单个interface的实现
life cycle(生命周期) 分块中,方法应该按照 实际声明周期的执行顺序 进行排列;
- 总结
针对 模块结构以及类结构 进行设计,能够让一个项目具有更好的自解析能力,让项目新人不用看代码细节,就能够大概了解 项目功能 和 类功能,从而降低代码的阅读难度。
对于一般的Android和iOS代码规范,由于系统以及开发语言的差异,导致两个平台的代码规范相差巨大;而对于 模块结构以及类结构 代码规范的设计,很大程度上是跨开发平台的,可以在Android和iOS上通用的。