最近在做一功能不大、业务也不复杂的小众App,以往做App是发现自己从来没有考虑过一些架构方面的问题,只是按照自己以往的习惯去写代码,忽略了App的设计。本次分享主要包含一些开发App的小经验和技巧,来一次App开发与设计的分享。

先和分享下一下**实体类的设计与组织形式**

### 实体类的组织

在做App开发的时候有很多的实体类,项目越复杂实体类就会越多,经过我的一番思考大致这可以将实体分为以下几大数:

* 面向数据库的
* 服务端返回的数据实体
* 用于渲染View的实体(使用Databinding)

一般情况下实体类的操作会经过以下步骤:

1. App请求服务器获取数据
2. 将数据存入数据库(可选)
3. 渲染页面展示数据

![21](https://img2018.cnblogs.com/blog/585087/201911/585087-20191122153944223-1662304384.png)

现在的实体的产生只用在请求服务器数据的时候才需要新建,后续的数据库、页面渲染其实是可以使用一套实体:

![22](https://img2018.cnblogs.com/blog/585087/201911/585087-20191122153944408-1718550849.png)

先不说这样做的行不行,首先三个地方使用同一实体就会引起字段歧义比如服务器数据有Id、本地数据也有Id,那两个id字段就有冲突了不得不改字段名。

另一种情况渲染和数据本身并不会一一对应,有时候后端数据给的是一个纯数字而前端页面显示的是字符串两个都对应不上,强行放在一起会起来更多的问题。

所为实体类的的正确组织形式应该是:**相互隔离、互不干扰**:

![23](https://img2018.cnblogs.com/blog/585087/201911/585087-20191122153944546-1321776412.png)

数据实体的在渲染之前都需要准备好,比如在ViewModel中将int型的数据转换成文本型的数据然后再使用Databinding+页面渲染实体来渲染页面。

### 优雅的处理网络数据

现在Android开发使用的网络库大部分都是`Okhttp + Retrofit`,使用Retrofit网络交互变的非常简单一个Service接口就能搞定一切,美兹兹~~,现在大部分后端返回的数据都会是以下形式:

```json
{
"code":0,
"data": {},
"msg": ""
}
```

虽然不能涵盖所有,但还是可以非常赞的数据、消息、成功与否啥都有!对于前面主要是关注`data`字段,其他`msg`、`code`等都属于辅助字段。前端对应的实体对象应该是这样的(假代码):

```java
public class ApiResponse {
private int code;
private T data;
private String msg;
}
```

对应的Service那就得定义成这样(使用了RxJava):

```java
public intface UserService {
@GET("/xx/{id}")
Single getUserInfoById(@Path("id") Long userId);
}
```

从接口中可以看出来,方法的返回值就包了几层,如果要拿`data`字段需要经过:`ApiResponse -> UserInfo`,而且在拿之前还要判断`code`字段:

```java

...

if(ApiResponse.code == 0){
UserInfo info = ApiResponse.getData();
}

...

```

为了消除这些冗余的代码可以使用`CallAdapter`来使Service方法返回的数据直接就是实体类:

```java
public intface UserService {
@GET("/xx/{id}")
Single getUserInfoById(@Path("id") Long userId);
}
```

`CallAdapter`的代码就不贴了,可以自行查找。这样做带来的另外一个问题就是**业务代码如何判断接口是否成功或失败**,前端必需友好的把错误提示给用户而不是一直搞个Loading在那里瞎转~~。现阶段最方便的的错误传递方式是使用**Java异常**,前端可以定义**业务异常**或**网络异常**:

```java
public class BizException extends RuntimeException {
...
}
```

在`CallAdapter`中检查ApiResponse的返回值是否成功:

```

if(!ApiResponse != 0){
throw new BizExcepiton(ApiResponse);
}

```

如果后端返回业务异常那前端就对应抛出一个`BizExcepiton`,如果是http错误如:404、400那可以抛出`HttpException`。除了`BizExcepiton`和`HttpException`外还可使用特定的异常比如后端返回密码错误异常:

```
public class InvalidPasswordException extends BizException {
...
}
```

如需特殊处理,也可以满足要求。

### 健壮的数据层

现在很多应用都开发使用MVVM开发模式数据层都使用`Repository`来表示,面向**数据驱动**的开发模式,页面变化都需要随着数据变更而更新,**数据发生变化然后页面再做出响应**。Repository的拆分要细一点,不建议简单的弄个`UserRepository`包含登陆、注册、更新密码等等操作,设计`Repository`的一些想法:

1. 面向接口编程
2. 保持**单一原则**
3. 功能边界要清晰(如:登陆、注册可以分开)
4. 业务逻辑尽可能的少(复杂的业务考虑Presenter)

一个判断是否是好的设计的办法可以这样:一个登陆页面从Activive/Fragment到ViewModel再到Repository,有没有多余的代码。比如上面说的`UserRepository`包含登陆、注册但是在一个登陆页面就不需要有注册功能,从登陆页面上来看注册的代码就是多余的(有些App登陆/注册在一个页面的~~)。

一个包含登陆、注册的`UserRepository`简单图:

![](https://img2018.cnblogs.com/blog/585087/201911/585087-20191122153944720-1390455330.png)

另外一点是尽量将repository使用到的一些东西集中管理,可引入一个基础的repository:

```java
public class SimpleRepository {

protected final T getService(Class clz){
return Services.getService(clz);
}
}

```

做为`SimpleRepository`的子类,就不需要考虑从哪里获取service的问题。

### 简洁的UI层

UI层面可以分为ViewModel和View(Activity/Fragment), View的职责应当只有二点:

1. 展示业务数据
2. 收集业务数据

例如一些数据的组织、判断都不应该出现在View中比如:
```java
if (Strings.isNullOrEmpty(phone)) {
...
return;
}

if (Strings.isNullOrEmpty(pwd)) {
...
return;
}
```

像上面这类的代码都不应该出现在View中,而在放置在ViewModel里面,View只**收集用户数据**传递给ViewModel由它来进行数据校验。再比如像这样的if/else代码也应该放置在ViewModel中:

```
int age = 10;
String desc = "";
if(age (this));
```

一旦数据发生变化`LiveData`就会通知Observer更新,通过DataBinding更新各个页面数据。

![](https://img2018.cnblogs.com/blog/585087/201911/585087-20191122153945197-2132211433.png)

再说ViewModel应该只包含一些简单的判断、检查、打通数据的代码,如果业务过于复杂可以考虑加Presetner,如果真的超级复杂那可以反思下这个复杂的逻辑应不应该放在前端,能不能放在后端呢?

欢迎关注微信公众号《架构文摘》,高质量技术文章第一时间推送。

![](https://img2018.cnblogs.com/blog/585087/201911/585087-20191122153945419-955963416.jpg)

高质量App的架构设计与思考!的更多相关文章

  1. [转]Android App整体架构设计的思考

    1. 架构设计的目的 对程序进行架构设计的原因,归根到底是为了提高生产力.通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合.这样做的好处是使得程序在开发的过程中,开发人员只需要专注于一点, ...

  2. Android App的架构设计:从VM、MVC、MVP到MVVM

    随着Android应用开发规模的扩大,客户端业务逻辑也越来越复杂,已然不是简单的数据展示了.如同后端开发遇到瓶颈时采用的组件拆分思想,客户端也需要进行架构设计,拆分视图和数据,解除模块之间的耦合,提高 ...

  3. 高性能、高可用、高扩展ERP系统架构设计

    ERP之痛 曾几何时,我混迹于电商.珠宝行业4年多,为这两个行业开发过两套大型业务系统(ERP).作为一个ERP系统,系统主要功能模块无非是订单管理.商品管理.生产采购.仓库管理.物流管理.财务管理等 ...

  4. app后端架构设计(转)

    (1)Restful设计原则 Restful风格:RESTfu设计原则,它被Roy Felding提出(在他的”基于网络的软件架构“论文中第五章).而REST的核心原则是将你的API拆分为逻辑上的资源 ...

  5. 王家林的81门一站式云计算分布式大数据&移动互联网解决方案课程第14门课程:Android软硬整合设计与框架揭秘: HAL&Framework &Native Service &App&HTML5架构设计与实战开发

    掌握Android从底层开发到框架整合技术到上层App开发及HTML5的全部技术: 一次彻底的Android架构.思想和实战技术的洗礼: 彻底掌握Andorid HAL.Android Runtime ...

  6. APP界面架构设计

    作为PM,信息架构和页面流的设计想必烂熟于心,当确定好产品战略层和范围层即为何种目标用户提供何种服务后,就要着手搭建功能架构,将目标功能通过良好的用户体验传递给用户,目的是高效解决用户痛点,从而实现价 ...

  7. APP系统架构设计初探

    一,图片体验的优化. 在手机上显示图片,速度是一个非常重要的体验点,试想,如果您打开一个网站,发现里面的图片一直显示失败或者是x,稍微做得好一点的,可能是一个不消失的loading或者是菊花等等,但不 ...

  8. 从MySQL高可用引出对高可用架构设计的一些思考

    高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间. 假设系统一直能够提供服务,我们说系统的可用性是100%.如果 ...

  9. 从mysql高可用架构看高可用架构设计

    高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间. 假设系统一直能够提供服务,我们说系统的可用性是100%.如果 ...

随机推荐

  1. SpringBoot系列:Spring Boot集成Spring Cache,使用RedisCache

    前面的章节,讲解了Spring Boot集成Spring Cache,Spring Cache已经完成了多种Cache的实现,包括EhCache.RedisCache.ConcurrentMapCac ...

  2. Python 爬取豆瓣TOP250实战

    学习爬虫之路,必经的一个小项目就是爬取豆瓣的TOP250了,首先我们进入TOP250的界面看看. 可以看到每部电影都有比较全面的简介.其中包括电影名.导演.评分等. 接下来,我们就爬取这些数据,并将这 ...

  3. 如何定制 Spring Boot 的 Banner?

    相信用过 Spring Boot 的朋友们一定在启动日志中见过类似如下的内容,比如在启动 Spring Boot 时,控制台默认会打印 Spring Boot Logo 以及版本信息,这是 Sprin ...

  4. Apache Flink 入门示例demo

    在本文中,我们将从零开始,教您如何构建第一个Apache Flink (以下简称Flink)应用程序. 开发环境准备 Flink 可以运行在 Linux, Max OS X, 或者是 Windows ...

  5. java秀发入门到优雅秃头路线导航【教学视频+博客+书籍整理】

    目录 一.Java基础 二.关于JavaWeb基础 三.关于数据库 四.关于ssm框架 五.关于数据结构与算法 六.关于开发工具idea 七.关于项目管理工具Mawen.Git.SVN.Gradle. ...

  6. 模块基础 day15

    目录 模块的四种形式 内置模块 pip安装的模块 自定义模块 包(模块) import和from···import 循环导入 模块的搜索路径 python文件的两种用途 模块的四种形式 模块就是一系列 ...

  7. TCP Socket服务端客户端(二)

    本文服务端客户端封装代码转自https://blog.csdn.net/zhujunxxxxx/article/details/44258719,并作了简单的修改. 1)服务端 此类主要处理服务端相关 ...

  8. 你编写的Java代码是咋跑起来的?

    如果你是一名 Java 开发人员,你肯定指定 Java 代码有很多种不同的运行方式.比如说可以在开发工具(IDEA.Eclipse等)中运行,可以双击执行 jar 文件运行,也可以在命令行中运行,甚至 ...

  9. Vue运用

    目录结构: ├── README.md 项目介绍 ├── index.html 入口页面 ├── build 构建脚本目录 │   ├── build-server.js 运行本地构建服务器,可以访问 ...

  10. 解决SAP740 GUI 搜索帮助(F4)回填值乱码的问题

    SAP 740客户端引入了搜索帮助增强功能,并且默认是开启该功能的,在带有F4搜索帮助的字段输入框中输入字段的前两个字符,可以自动以下拉框的方式带出包含包含所输入字符的条目,从而实现快速的输入帮助,如 ...