2188 字
约 7 分钟
2
为什么项目中总喜欢封装工具类?——从图片上传理解"解耦"思想

为什么项目中总喜欢封装工具类?——从图片上传理解"解耦"思想

前言

刚开始学习 Android 或 Java 开发时,我一直有一个疑问:

明明几行 Retrofit 就能上传图片,为什么很多公司的项目还要封装一个 ImageUploadUtilUploadManagerImageRepository

后来接触的项目越来越多,才发现:

真正要封装的不是图片上传,而是"变化"。

图片上传只是一个例子,它背后体现的是软件开发中非常重要的思想——解耦(Decoupling)

本文就以图片上传为例,聊聊什么是解耦、什么时候需要解耦,以及项目中常见的解耦方式。


一、什么是耦合?

在软件开发中,**耦合(Coupling)**表示模块之间的依赖程度。

举一个最简单的例子。

假设发布动态页面需要上传图片。

如果代码这样写:

public void publish() {

    MultipartBody.Part part =
            MultipartBody.Part.createFormData(
                    "file",
                    file.getName(),
                    RequestBody.create(file, MEDIA_TYPE)
            );

    api.upload(part)
            .enqueue(new Callback<UploadBean>() {

                @Override
                public void onResponse(...) {

                    // 获取图片地址

                    // 发布动态
                }

                @Override
                public void onFailure(...) {

                }
            });

}

此时:

PublishActivity
        │
        │
        ▼
Retrofit 上传接口

发布页面不仅负责页面逻辑,还负责:

  • 图片压缩
  • Multipart 创建
  • Retrofit 请求
  • 上传失败处理
  • 获取图片 URL

可以看到:

页面和上传逻辑紧紧绑在了一起。

这就是耦合。


二、为什么高耦合不好?

很多人会说:

能运行不就行了吗?

小项目确实没问题。

但是项目一大,就开始出现各种问题。

例如:

项目有五个页面都要上传图片。

头像上传

发布动态

聊天发送图片

意见反馈

商品上传

每个页面都写一遍:

MultipartBody.Part.createFormData(...)

api.upload(...)

enqueue(...)

结果就是:

AvatarActivity

PublishActivity

FeedbackActivity

ChatActivity

GoodsActivity

里面都有几乎一样的上传代码。

以后服务器修改接口:

/upload

改成:

/api/v2/upload

你需要修改:

  • AvatarActivity
  • PublishActivity
  • FeedbackActivity
  • ChatActivity
  • GoodsActivity

如果项目有二十多个页面,就意味着:

同一件事情需要修改二十多次。

这就是高耦合带来的维护成本。


三、什么是解耦?

解耦,就是:

降低模块之间的依赖,让每个模块只负责自己的事情。

例如,把上传代码抽出来。

PublishActivity
        │
        ▼
UploadManager
        │
        ▼
Retrofit

以后页面只需要:

uploadManager.upload(file);

页面根本不知道:

  • Multipart 怎么创建
  • Retrofit 怎么请求
  • Token 怎么携带
  • 图片怎么压缩

它只知道:

我要上传图片。

上传的所有细节,都交给 UploadManager。

这就是解耦。


四、为什么要解耦?

1、减少重复代码

以前:

Activity A

上传代码

Activity B

上传代码

Activity C

上传代码

现在:

Activity A
        │
Activity B
        │
Activity C
        │
        ▼
UploadManager

所有页面共享同一套上传逻辑。

以后修改一次即可。


2、隐藏复杂逻辑

真正的上传,其实远没有想象中简单。

一个完整流程可能是:

选择图片

↓

检查格式

↓

检查大小

↓

图片压缩

↓

读取 EXIF

↓

修正旋转角度

↓

生成 RequestBody

↓

生成 Multipart

↓

上传服务器

↓

失败重试

↓

返回 URL

如果全部写到 Activity:

一个页面可能有几百行代码。

真正属于页面的代码:

点击按钮

刷新 UI

显示加载框

可能只有几十行。

其他全部都是上传逻辑。

这显然是不合理的。

所以:

Activity 负责页面。

UploadManager 负责上传。

职责更加明确。


3、方便修改

今天:

Retrofit 上传

明天:

公司改成:

阿里云 OSS

或者:

腾讯 COS

甚至:

MinIO

如果所有页面直接调用 Retrofit:

整个项目全部修改。

如果所有页面调用:

uploadManager.upload(file);

只需要修改 UploadManager 即可。

页面完全不用动。


4、统一处理异常

上传可能失败:

网络错误

Token 过期

服务器异常

图片太大

格式错误

如果每个页面自己处理:

整个项目的提示信息可能都不同。

例如:

页面 A:

Toast("上传失败")

页面 B:

Toast("网络异常")

页面 C:

Dialog("请稍后再试")

用户体验非常混乱。

如果统一放到 UploadManager:

所有上传异常都按照统一规范处理。

维护也更加方便。


五、什么时候应该解耦?

很多初学者有一个误区:

任何代码都应该封装。

其实不是。

解耦不是为了封装而封装。

而是当代码开始"变化"或者"重复"的时候,再考虑解耦。

通常有下面几种情况。


第一种:重复代码

例如:

三个页面都有:

api.login(...)

那么:

登录逻辑可以抽出来。

例如:

LoginRepository

第二种:一个类职责太多

例如:

MainActivity

里面:

  • 登录
  • 上传图片
  • 下载文件
  • 数据库操作
  • 网络请求
  • 权限申请

一个类几千行。

这种情况就应该拆分。


第三种:未来可能经常变化

例如:

支付。

今天:

微信支付

明天:

支付宝

后天:

银联

支付方式一直在变。

所以支付模块应该独立。

上传也是一样。


第四种:多个模块共同使用

例如:

图片加载。

如果:

首页

详情页

聊天

个人中心

都需要加载图片。

那么:

图片加载就应该统一封装。

例如:

ImageLoader

以后 Glide 换成 Coil。

只需要改一个地方。


六、常见的解耦方式

项目中最常见的几种方式如下。

① 工具类(Util)

适合:

没有状态。

纯工具方法。

例如:

DateUtil

StringUtil

MD5Util

② Manager

负责管理某一类业务。

例如:

UploadManager

DownloadManager

LocationManager

③ Repository

MVVM 中最常见。

负责数据来源。

例如:

UserRepository

ImageRepository

LoginRepository

Repository 不关心数据来自哪里。

可能来自:

网络

数据库

缓存

调用者完全不用关心。


④ 接口 + 实现

例如:

interface Upload {

    void upload(File file);

}

实现:

OssUpload

CosUpload

LocalUpload

以后切换实现。

业务代码完全不用改。

这种方式也是大型项目最常见的解耦方式。


七、解耦不是目的,而是降低维护成本

很多人学习设计模式的时候,总想着:

我要把所有东西都抽出来。

其实这是错误的。

如果一个 Demo:

只有一个页面。

只有一次上传。

完全没必要:

UploadManager

UploadRepository

UploadFactory

UploadStrategy

UploadCallback

UploadHelper

这样反而增加了复杂度。

真正的原则应该是:

简单的代码保持简单,复杂的代码再进行解耦。

随着业务增长,再逐步拆分。

这也是很多成熟项目采用的演进方式。


总结

解耦并不是一种高深的技术,而是一种编程思想。

它的核心目标只有一个:

让每个模块只负责自己的事情,把容易变化的部分隔离出来,从而降低维护成本。

以图片上传为例,真正需要封装的不是 Retrofit,而是上传这一整套能力。

当上传逻辑集中到 UploadManagerRepository 等模块后,页面只需要关心"我要上传图片",而不用关心"图片是怎么上传的"。

写代码时,可以始终问自己两个问题:

  1. 这段代码会不会在多个地方重复出现?
  2. 这段代码以后会不会经常变化?

如果答案是"会",那么它就很可能值得解耦。

优秀的软件设计,不是把代码写得更复杂,而是把变化控制在最小的范围内。当一个需求变更时,只需要修改一个地方,而不是整个项目,这就是解耦真正的价值。

为什么项目中总喜欢封装工具类?——从图片上传理解"解耦"思想
http://www.clxhxhhr.top/posts/373/
作者
clxstart
发布于
2026-08-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。