前言
移动应用遗留系统重构(5)- 重构方法篇中我们分享了重构流程,主要为4个操作步骤。
- 识别一个内聚的包
- 解除该包的异常依赖
- 移动该包对应的代码及资源到新的模块
- 包解耦验收
移动应用遗留系统重构(6)- 测试篇中我们为CloudDisk补充了一组基本的冒烟测试。有了基本的测试守护后,本篇我们将挑选library(基础组件库)及file(文件业务模块)2个包进行重构演示。文章中包含操作的流程,同时了录制了视频。
library模块重构代码演示视频:mp.weixin.qq.com/s/C0nQRbgmp…
file模块重构代码演示视频:mp.weixin.qq.com/s/xbAIu6bWS…
安全重构演示
library包重构
- 依赖分析
通过分析我们发现library包存在对上层模块的反向依赖,该依赖为异常依赖,须要解除。
- 安全重构
重构前代码:
public class HttpUtils {
public static void post(String url) {
//发送http post请求,需要用到userId做标识
String params = UserController.userId;
}
public static void get(String url) {
//发送http get请求,需要用到userId做标识
String params = UserController.userId;
}
}
复制代码
重构手法:提取方法参数
重构后代码:
public class HttpUtils {
public static void post(String url, String userId) {
//发送http post请求,需要用到userId做标识
String params = userId;
}
public static void get(String url, String userId) {
//发送http get请求,需要用到userId做标识
String params = userId;
}
}
复制代码
- 代码移动
代码移动至独立的library,加上对应的Gradle依赖:
移动后模块结构如下:
- 功能验证
执行冒烟测试,验证功能
./gradlew app:testDebug --tests SmokeTesting
复制代码
代码演示:mp.weixin.qq.com/s/C0nQRbgmp…
具体的代码:github链接
file包重构
- 依赖分析
通过分析我们发现file包存在横向bundle模块的依赖,该依赖为异常依赖,须要解除。
- 安全重构
重构前代码:
public class FileController {
public List<FileInfo> getFileList() {
return new ArrayList<>();
}
public FileInfo upload(String path) {
//上传文件
LogUtils.log("upload file");
HttpUtils.post("http://file", UserController.userId);
return new FileInfo();
}
public FileInfo download(String url) {
//下载文件
if (!UserController.isLogin) {
return null;
}
return new FileInfo();
}
}
复制代码
重构手法:
2.1 抽取getUserId、isLogin方法
重构后代码如下:
public class FileController {
public List<FileInfo> getFileList() {
return new ArrayList<>();
}
public FileInfo upload(String path) {
//上传文件
LogUtils.log("upload file");
HttpUtils.post("http://file", getUserId());
return new FileInfo();
}
public FileInfo download(String url) {
//下载文件
if (!isLogin()) {
return null;
}
return new FileInfo();
}
private String getUserId() {
return UserController.userId;
}
private boolean isLogin() {
return UserController.isLogin;
}
}
复制代码
2.2 抽取代理类,UserState
重构后代码如下:
public class FileController {
private final UserState userState = new UserState();
public List<FileInfo> getFileList() {
return new ArrayList<>();
}
public FileInfo upload(String path) {
//上传文件
LogUtils.log("upload file");
HttpUtils.post("http://file", userState.getUserId());
return new FileInfo();
}
public FileInfo download(String url) {
//下载文件
if (!userState.isLogin()) {
return null;
}
return new FileInfo();
}
}
复制代码
2.3 抽取接口
重构后代码如下:
public class FileController {
private final UserState userState = new UserStateImpl();
public List<FileInfo> getFileList() {
return new ArrayList<>();
}
public FileInfo upload(String path) {
//上传文件
LogUtils.log("upload file");
HttpUtils.post("http://file", userState.getUserId());
return new FileInfo();
}
public FileInfo download(String url) {
//下载文件
if (!userState.isLogin()) {
return null;
}
return new FileInfo();
}
}
复制代码
2.4 提取构造函数,依赖接口注入
重构后代码如下:
public class FileController {
private final UserState userState;
public FileController(UserState userState) {
this.userState = userState;
}
public List<FileInfo> getFileList() {
return new ArrayList<>();
}
public FileInfo upload(String path) {
//上传文件
LogUtils.log("upload file");
HttpUtils.post("http://file", userState.getUserId());
return new FileInfo();
}
public FileInfo download(String url) {
//下载文件
if (!userState.isLogin()) {
return null;
}
return new FileInfo();
}
}
复制代码
同样FileFragment我也也做相同的构造及接口注入。
- 代码移动
同样使用moduraize进行移动,代码移动至独立的fileBundle,加上对应的Gradle依赖:
移动后模块结构如下:
- 功能验证
执行冒烟测试,验证功能
./gradlew app:testDebug --tests SmokeTesting
复制代码
每一小步重构时都可以频繁运行测试,提前发现问题
代码演示:mp.weixin.qq.com/s/xbAIu6bWS…
具体的代码:github链接
总结
本篇我们按着重构的4个步骤,借助IDE的安全重构,小步的重构了library和file2个包。虽然依赖解除了,代码也移动到独立的模块里面。但是我们还是发现了一些问题。
- UserState接口的层层注入,我们需要手工维护了好多构造方法及对应的注入
- App依赖了fileBundle的Fragment,UI跳转上存在编译的依赖
下一篇,单体移动应用“模块化”演进之旅(8)- 依赖注入篇,我们将分享常见的注入方式及业内优秀的实践,并对DiskCloud继续进行改造优化。
CloudDisk示例代码
系列链接
大纲
关于
欢迎关注CAC敏捷教练公众号。微信搜索:CAC敏捷教练。