本文整理 android 开发中常见技术点对应的设计模式,并给出简化伪代码、典型源码/原理使用位置。伪代码用于理解模式结构,不等同于源码实现。
总览
| 设计模式 | android 常见技术点 | 典型使用位置 |
|---|---|---|
| 单例模式 | 全局管理器、系统服务、数据库实例 | workmanager.getinstance()、room.databasebuilder() 后的数据库单例、systemserviceregistry |
| builder 模式 | 复杂对象构建 | alertdialog.builder、notificationcompat.builder、room.databasebuilder() |
| 工厂模式 | 对象创建解耦 | layoutinflater.factory2、fragmentfactory、viewmodelprovider.factory |
| 观察者模式 | 数据变化通知、生命周期感知 | livedata.observe()、lifecycleobserver、flow.collect |
| 适配器模式 | 数据和 ui 解耦 | recyclerview.adapter、listadapter、cursoradapter |
| 代理模式 | ipc、远程服务、本地接口代理 | binder 的 stub / proxy、aidl |
| 装饰器模式 | 包装并增强能力 | contextwrapper、contextthemewrapper、inputstream 包装链 |
| 外观模式 | 简化复杂子系统访问 | context、camerax、glide.with() |
| 模板方法模式 | 固定流程中暴露可重写步骤 | activity 生命周期、view.draw()、viewgroup.dispatchdraw() |
| 策略模式 | 可替换算法或行为 | recyclerview.layoutmanager、itemanimator、diffutil.itemcallback |
| 责任链模式 | 事件分发、拦截链 | 触摸事件分发、okhttp interceptor |
| 状态模式 | 对象行为随状态变化 | lifecycle.state、播放器状态、登录状态 |
| 命令模式 | 把操作封装为对象 | runnable + handler、pendingintent、点击事件回调 |
| mvc / mvp / mvvm | 应用架构分层 | activity/fragment、viewmodel、livedata/stateflow、repository |
1. 单例模式 singleton
使用场景
- 应用内只有一个实例:数据库、配置中心、线程池、日志工具。
- android 系统服务通过统一入口获取共享服务。
- 避免重复创建重资源对象。
android 中的例子
workmanager.getinstance(context)roomdatabase通常在应用层做单例封装systemserviceregistry管理系统服务实例application全局生命周期入口
伪代码
class appdatabase private constructor() {
companion object {
@volatile
private var instance: appdatabase? = null
fun getinstance(): appdatabase {
return instance ?: synchronized(this) {
instance ?: appdatabase().also { instance = it }
}
}
}
}
源码 / 原理标注
context.getsystemservice()背后会从系统服务注册表中按名称获取服务。workmanager通过getinstance()对外提供统一入口,内部保证调度组件可被全局访问。- room 数据库实例创建成本较高,官方实践通常建议在应用进程内复用单例。
2. builder 模式
使用场景
- 对象参数很多,构造函数会变得臃肿。
- 创建过程需要链式配置。
- 最终通过
build()或create()生成目标对象。
android 中的例子
alertdialog.buildernotificationcompat.builderroom.databasebuilder(context, appdatabase::class.java, "db").build()workrequest.builder
伪代码
class dialog private constructor(
val title: string?,
val message: string?,
val cancelable: boolean
) {
class builder {
private var title: string? = null
private var message: string? = null
private var cancelable: boolean = true
fun settitle(value: string) = apply { title = value }
fun setmessage(value: string) = apply { message = value }
fun setcancelable(value: boolean) = apply { cancelable = value }
fun build(): dialog {
return dialog(title, message, cancelable)
}
}
}
源码 / 原理标注
alertdialog.builder先收集标题、按钮、布局等配置,最后调用create()构建alertdialog。notificationcompat.builder把通知图标、标题、内容、渠道等复杂参数集中封装,降低构造复杂度。- room 的 builder 会配置数据库名、迁移策略、线程策略,最后创建数据库实例。
3. 工厂模式 factory
使用场景
- 调用方不直接依赖具体类构造函数。
- 根据条件创建不同对象。
- 框架希望把对象创建权开放给开发者定制。
android 中的例子
layoutinflater.factory2创建 viewfragmentfactory创建 fragmentviewmodelprovider.factory创建 viewmodelserviceloader或依赖注入框架中的对象创建
伪代码
interface viewmodelfactory {
fun <t : viewmodel> create(modelclass: class<t>): t
}
class userviewmodelfactory(
private val repository: userrepository
) : viewmodelfactory {
override fun <t : viewmodel> create(modelclass: class<t>): t {
if (modelclass == userviewmodel::class.java) {
return userviewmodel(repository) as t
}
error("unknown viewmodel")
}
}
源码 / 原理标注
viewmodelprovider不知道业务viewmodel如何构造,于是通过factory把创建过程交给调用方。layoutinflater解析 xml 时,需要把标签名转换成具体view对象,这就是典型的创建型模式场景。fragmentfactory允许 fragment 使用带参数构造或依赖注入方式创建,避免框架只能调用空构造。
4. 观察者模式 observer
使用场景
- 一个对象状态变化,需要通知多个观察者。
- ui 自动响应数据变化。
- 生命周期变化需要通知监听者。
android 中的例子
livedata.observe(owner, observer)lifecycle.addobserver(observer)stateflow/sharedflowtextwatcher、broadcastreceiver
伪代码
class observabledata<t> {
private val observers = mutablelistof<(t) -> unit>()
private var value: t? = null
fun observe(observer: (t) -> unit) {
observers += observer
value?.let(observer)
}
fun setvalue(newvalue: t) {
value = newvalue
observers.foreach { it(newvalue) }
}
}
源码 / 原理标注
livedata保存观察者列表,数据变化后分发给活跃生命周期状态下的观察者。lifecycleregistry内部维护观察者,并在activity/fragment生命周期变化时派发生命周期事件。broadcastreceiver可以理解为系统级发布订阅机制,发送广播后匹配的接收者会收到通知。
5. 适配器模式 adapter
使用场景
- 将一种接口转换成另一种接口。
- 数据结构和 ui 展示组件不直接耦合。
- 让已有数据适配目标控件协议。
android 中的例子
recyclerview.adapterlistadaptercursoradapterpageradapter
伪代码
class useradapter(
private val users: list<user>
) : recyclerview.adapter<userviewholder>() {
override fun getitemcount(): int {
return users.size
}
override fun oncreateviewholder(parent: viewgroup, viewtype: int): userviewholder {
return userviewholder(parent.inflate("item_user"))
}
override fun onbindviewholder(holder: userviewholder, position: int) {
holder.bind(users[position])
}
}
源码 / 原理标注
recyclerview不关心数据来源,只依赖adapter提供数量、创建 viewholder、绑定数据。cursoradapter把数据库查询结果cursor适配成列表项视图。listadapter在适配器基础上加入diffutil,让列表更新更高效。
6. 代理模式 proxy
使用场景
- 调用方访问的是代理对象,代理对象再转发给真实对象。
- 可以隐藏跨进程、远程、权限校验、缓存等复杂细节。
- android ipc 是代理模式的经典场景。
android 中的例子
- binder ipc 中的
stub和proxy - aidl 自动生成代码
- 系统服务接口,例如
activitymanager、packagemanager
伪代码
interface iuserservice {
fun getusername(id: long): string
}
class userserviceproxy(
private val remotebinder: binder
) : iuserservice {
override fun getusername(id: long): string {
val data = parcel.obtain()
val reply = parcel.obtain()
data.writelong(id)
remotebinder.transact(code_get_user, data, reply, 0)
return reply.readstring()
}
}
源码 / 原理标注
- aidl 会生成
stub和proxy:本地进程调用接口方法,实际由proxy封装参数并通过 binder 发送到远端。 - 客户端拿到的很多系统服务接口并不是真实服务对象,而是 binder 代理。
proxy屏蔽了进程边界,让跨进程调用看起来像普通方法调用。
7. 装饰器模式 decorator
使用场景
- 不修改原类的情况下增强对象能力。
- 多层包装,逐步叠加功能。
- 保持原始接口一致。
android 中的例子
contextwrappercontextthemewrapper- java io 中的
bufferedinputstream(inputstream) - appcompat 中对
context和view的包装增强
伪代码
open class basecontext {
open fun getthemename(): string = "default"
}
open class contextwrapper(
private val base: basecontext
) : basecontext() {
override fun getthemename(): string {
return base.getthemename()
}
}
class themecontextwrapper(
base: basecontext,
private val theme: string
) : contextwrapper(base) {
override fun getthemename(): string {
return theme
}
}
源码 / 原理标注
contextwrapper内部持有一个base context,默认把大部分调用委托给它。contextthemewrapper在原有context基础上叠加主题能力。activity本身也继承自contextthemewrapper,因此具备上下文和主题相关能力。
8. 外观模式 facade
使用场景
- 对外暴露简单接口,内部封装复杂子系统。
- 降低调用方理解成本。
- 常用于 sdk、框架入口、工具库入口。
android 中的例子
context封装资源、文件、服务、启动组件等能力glide.with(context).load(url).into(imageview)camerax相比 camera2 提供更简单的相机 apinavcontroller封装 fragment 事务和回退栈
伪代码
class imageloaderfacade(
private val cache: imagecache,
private val network: imagenetwork,
private val decoder: imagedecoder
) {
fun load(url: string, imageview: imageview) {
val bytes = cache.get(url) ?: network.download(url)
val bitmap = decoder.decode(bytes)
imageview.setimagebitmap(bitmap)
}
}
源码 / 原理标注
context是 android 应用访问系统能力的重要外观,调用方无需知道资源管理器、包管理器、服务管理器的内部细节。camerax把 camera2 中复杂的设备枚举、session、capturerequest 封装成更容易使用的用例 api。navcontroller把导航图、参数、fragment 切换、返回栈管理封装成统一入口。
9. 模板方法模式 template method
使用场景
- 父类定义算法骨架。
- 子类只重写流程中的部分步骤。
- 框架控制整体流程,业务代码填充细节。
android 中的例子
activity.oncreate()、onstart()、onresume()fragment生命周期view.draw()中的测量、绘制、子 view 绘制流程baseadapter.getview()
伪代码
abstract class baseactivity {
fun performcreate() {
attachbasecontext()
oncreate()
restorestate()
}
protected open fun attachbasecontext() {}
protected abstract fun oncreate()
protected open fun restorestate() {}
}
class mainactivity : baseactivity() {
override fun oncreate() {
setcontentview("activity_main")
}
}
源码 / 原理标注
- android framework 决定生命周期调用顺序,开发者只重写指定回调。
view.draw()内部大致按背景、内容、子 view、前景等步骤绘制,子类可重写ondraw()填充自定义绘制。- 模板方法体现了“框架调用业务代码”的控制反转思想。
10. 策略模式 strategy
使用场景
- 同一个上下文中切换不同算法或行为。
- 行为对象可以独立替换。
- 减少大量
if else。
android 中的例子
recyclerview.layoutmanagerrecyclerview.itemanimatordiffutil.itemcallback- 动画插值器
interpolator
伪代码
interface sortstrategy {
fun sort(items: list<item>): list<item>
}
class timesortstrategy : sortstrategy {
override fun sort(items: list<item>) = items.sortedby { it.time }
}
class namesortstrategy : sortstrategy {
override fun sort(items: list<item>) = items.sortedby { it.name }
}
class itemcontroller(
private var strategy: sortstrategy
) {
fun render(items: list<item>) {
show(strategy.sort(items))
}
}
源码 / 原理标注
recyclerview通过替换linearlayoutmanager、gridlayoutmanager、staggeredgridlayoutmanager改变布局策略。interpolator决定动画数值随时间变化的策略,例如线性、加速、减速。diffutil.itemcallback把“如何判断两个 item 是否相同”的策略交给业务层。
11. 责任链模式 chain of responsibility
使用场景
- 请求沿着一条链传递。
- 链上每个节点都有机会处理或继续传递。
- 常用于事件分发、请求拦截、日志处理。
android 中的例子
- 触摸事件分发:
activity->window->decorview->viewgroup->view viewgroup.dispatchtouchevent()、onintercepttouchevent()、ontouchevent()okhttp interceptor拦截器链
伪代码
abstract class eventnode {
var next: eventnode? = null
fun dispatch(event: motionevent): boolean {
if (handle(event)) {
return true
}
return next?.dispatch(event) ?: false
}
protected abstract fun handle(event: motionevent): boolean
}
源码 / 原理标注
- 触摸事件先到
activity.dispatchtouchevent(),再进入window和根 view。 viewgroup可以通过onintercepttouchevent()决定是否拦截事件。- 如果子 view 不消费事件,事件可能回到父容器或自身的
ontouchevent()继续处理。 - okhttp 的应用拦截器、重试拦截器、缓存拦截器、网络拦截器按链式顺序处理请求。
12. 状态模式 state
使用场景
- 对象在不同状态下行为不同。
- 状态转换规则比较清晰。
- 避免状态相关逻辑散落在多个条件分支中。
android 中的例子
lifecycle.state- 播放器状态:idle、preparing、playing、paused、completed
- 登录状态:guest、loggedin、expired
- 下载任务状态:pending、running、success、failed
伪代码
interface playerstate {
fun play(player: player)
fun pause(player: player)
}
class idlestate : playerstate {
override fun play(player: player) {
player.prepare()
player.state = playingstate()
}
override fun pause(player: player) {
// idle 状态下无需处理
}
}
class playingstate : playerstate {
override fun play(player: player) {}
override fun pause(player: player) {
player.pauseinternal()
player.state = pausedstate()
}
}
源码 / 原理标注
lifecycleregistry会在生命周期事件发生时推进内部状态,例如initialized、created、started、resumed。- ui 层常用状态驱动渲染,例如 loading、content、empty、error。
- 播放器、下载器、上传器这类组件很适合用状态模式管理行为。
13. 命令模式 command
使用场景
- 把一个操作封装成对象。
- 操作可以延迟执行、排队执行、撤销或重试。
- 调用者和执行者解耦。
android 中的例子
runnable投递到handlerpendingintentview.onclicklistenerworkrequest
伪代码
interface command {
fun execute()
}
class saveusercommand(
private val repository: userrepository,
private val user: user
) : command {
override fun execute() {
repository.save(user)
}
}
class commandqueue {
private val commands = arraydeque<command>()
fun enqueue(command: command) {
commands.addlast(command)
}
fun runnext() {
commands.removefirstornull()?.execute()
}
}
源码 / 原理标注
handler.post(runnable)把一段逻辑封装为runnable,放入消息队列等待主线程或工作线程执行。pendingintent把未来要执行的启动 activity、service、broadcast 操作交给系统保存并触发。workrequest把后台任务的执行条件、输入数据、调度要求封装起来,由 workmanager 统一执行。
14. mvc / mvp / mvvm 架构模式
使用场景
- 组织应用层代码职责。
- 降低 ui、业务逻辑、数据源之间的耦合。
- 提高可测试性和可维护性。
android 中的例子
- mvc:早期
activity同时承担 controller 和部分 view 职责。 - mvp:
activity/fragment作为 view,presenter 处理业务逻辑。 - mvvm:
viewmodel暴露状态,activity/fragment/compose负责渲染。 - repository:隔离网络、数据库、缓存等数据来源。
伪代码
class userviewmodel(
private val repository: userrepository
) : viewmodel() {
private val _uistate = mutablestateflow<useruistate>(useruistate.loading)
val uistate: stateflow<useruistate> = _uistate
fun loaduser(id: long) {
viewmodelscope.launch {
_uistate.value = useruistate.loading
_uistate.value = runcatching {
repository.getuser(id)
}.fold(
onsuccess = { useruistate.content(it) },
onfailure = { useruistate.error(it.message.orempty()) }
)
}
}
}
class userfragment : fragment() {
private val viewmodel: userviewmodel by viewmodels()
fun render() {
collect(viewmodel.uistate) { state ->
when (state) {
is useruistate.loading -> showloading()
is useruistate.content -> showuser(state.user)
is useruistate.error -> showerror(state.message)
}
}
}
}
源码 / 原理标注
viewmodel生命周期长于配置变化后的activity/fragment重建,适合保存 ui 状态。livedata/stateflow让 view 观察状态变化,体现观察者模式。- repository 隔离数据来源,让 ui 层不直接依赖 retrofit、room、datastore 等具体实现。
- jetpack compose 中常见的
state -> ui思路也是 mvvm / 单向数据流思想的延伸。
15. 组合模式 composite
使用场景
- 树形结构中,单个对象和组合对象使用统一接口。
- 调用方可以一致地处理叶子节点和容器节点。
android 中的例子
view和viewgroup- 菜单结构
menu/menuitem - compose ui 树
伪代码
abstract class uinode {
abstract fun draw()
}
class textnode : uinode() {
override fun draw() {
drawtext()
}
}
class containernode : uinode() {
private val children = mutablelistof<uinode>()
fun add(child: uinode) {
children += child
}
override fun draw() {
children.foreach { it.draw() }
}
}
源码 / 原理标注
viewgroup继承自view,因此容器本身也是一个 view。viewgroup内部持有子 view 列表,测量、布局、绘制时会递归处理子节点。- compose 运行时维护 ui 组合树,状态变化后按树结构进行重组和更新。
16. 享元模式 flyweight
使用场景
- 大量相似对象共享内部状态,减少内存开销。
- 缓存可复用对象。
- 图片、字符串、资源对象等都可能用到共享思想。
android 中的例子
bitmap缓存recyclerview复用viewholder- 资源系统复用
drawable、colorstatelist等资源数据 - 字符串常量池
伪代码
class bitmappool {
private val cache = mutablemapof<string, bitmap>()
fun get(key: string, loader: () -> bitmap): bitmap {
return cache[key] ?: loader().also { bitmap ->
cache[key] = bitmap
}
}
}
源码 / 原理标注
recyclerview通过回收池复用 viewholder,避免列表滑动时频繁创建 view。- 图片加载库通常使用内存缓存、磁盘缓存、bitmap 池降低内存抖动。
- android 资源加载系统会缓存部分资源,避免重复解析和创建。
记忆方式
| 你在做什么 | 常见模式 |
|---|---|
| 创建复杂对象 | builder |
| 控制对象唯一 | singleton |
| 把创建权交出去 | factory |
| 数据变了通知 ui | observer |
| 数据接到列表控件 | adapter |
| 跨进程像本地调用 | proxy |
| 包一层增强功能 | decorator |
| 给复杂系统一个简单入口 | facade |
| 框架定流程,业务填步骤 | template method |
| 替换算法或行为 | strategy |
| 请求一路传递 | chain of responsibility |
| 不同状态不同行为 | state |
| 操作排队或延迟执行 | command |
| 树形 ui 统一处理 | composite |
| 大量对象共享复用 | flyweight |
学习建议
- 看源码时先问:这个类是在创建对象、转发调用、分发事件、保存状态,还是适配数据?
- android framework 很多模式不是“标准教科书写法”,而是为了生命周期、ipc、ui 树、线程模型做了工程化变体。
- 面试回答时建议按“三段式”:先说模式定义,再说 android 例子,最后说源码或原理中的关键调用链。
到此这篇关于android常用设计模式速查一览表的文章就介绍到这了,更多相关android常用设计模式内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论