1) Observer(观察者)
落点:LiveData / Flow + Lifecycle
动机:UI 随数据变化自动更新,并与生命周期解耦。
kotlin
class UserVM : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User> = _user
}
class ProfileFragment : Fragment(R.layout.frag) {
private val vm: UserVM by viewModels()
override fun onViewCreated(v: View, s: Bundle?) {
vm.user.observe(viewLifecycleOwner) { ui -> render(ui) } // 只在 STARTED 以后回调
}
}
要点
- LiveData 内部会根据 Lifecycle.State 自动添加/移除 observer(避免泄漏)。
- StateFlow/Flow 同样是观察者模型,但不关心生命周期,要配合 repeatOnLifecycle。
2) Mediator(中介者)
落点 A:MediatorLiveData(多源聚合)
落点 B:Paging 3 的 RemoteMediator(本地缓存 + 远端分页的协作"中枢")
ini
val fullName = MediatorLiveData<String>().apply {
addSource(firstName) { v -> value = "$v ${lastName.value}" }
addSource(lastName) { v -> value = "${firstName.value} $v" }
}
kotlin
@OptIn(ExperimentalPagingApi::class)
class ArticleMediator(
private val service: Api, private val db: AppDb
) : RemoteMediator<Int, Article>() {
override suspend fun load(loadType: LoadType, state: PagingState<Int, Article>)
: MediatorResult {
// 统一协调:决定请求页、下发网络、落库、告知是否 endOfPagination
}
}
要点
- MediatorLiveData 把多个 LiveData 的变更集中协调,避免互相观察的网状依赖。
- RemoteMediator 把"网络页码/边界"与"本地分页源"解耦,是 Paging 3 的灵魂。
3) Repository(仓库)
落点:Google 官方架构建议(Repository 作为 UI 与数据源门面)。
动机:隐藏数据来源(DB/网络/缓存/文件),对上层暴露统一 API。
kotlin
class UserRepo @Inject constructor(
private val api: Api, private val dao: UserDao
) {
fun user(id: Long): Flow<User> =
dao.observe(id).onStart {
val net = api.loadUser(id)
dao.insert(net)
}
}
要点
- 上层(ViewModel/UI)只依赖 Repository 接口,便于测试与替换实现(Fake/Mock)。
4) Factory(工厂)
落点:ViewModelProvider.Factory / AbstractSavedStateViewModelFactory
动机:创建带参数/带 SavedStateHandle 的 ViewModel。
kotlin
class DetailVM(private val repo: Repo, private val id: Long) : ViewModel()
class DetailVMFactory(
owner: SavedStateRegistryOwner, private val repo: Repo, defaultArgs: Bundle?
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
override fun <T: ViewModel> create(key: String, model: Class<T>, state: SavedStateHandle): T {
val id = state.get<Long>("id")!!
return DetailVM(repo, id) as T
}
}
要点
- 不用 Hilt 时,工厂是最标准创建路径;用 Hilt 则由 DI 容器"接管工厂"。
5) Singleton(单例)
落点:RoomDatabase、DataStore、Retrofit(虽不属 Jetpack,但常并用)
动机:昂贵对象(连接池、DB)的全局唯一实例。
kotlin
@Database(entities = [User::class], version = 1)
abstract class AppDb : RoomDatabase() {
companion object {
@Volatile private var INSTANCE: AppDb? = null
fun get(context: Context) = INSTANCE ?: synchronized(this) {
INSTANCE ?: Room.databaseBuilder(context, AppDb::class.java, "app.db").build()
.also { INSTANCE = it }
}
}
}
6) Builder(生成器)
落点 A:WorkManager 的 OneTimeWorkRequestBuilder / Constraints.Builder
落点 B:Navigation Kotlin DSL 构建图;Compose ConstraintSet 也体现 Builder 味道。
scss
val work = OneTimeWorkRequestBuilder<UploadWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.build()
).build()
WorkManager.getInstance(ctx).enqueue(work)
要点
- 将复杂对象的可选参数分步构造,结尾 build() 收口,防止构造函数爆炸。
7) Strategy(策略)
落点 A:DiffUtil.ItemCallback(比较策略可插拔)
落点 B:LinearLayoutManager/GridLayoutManager(布局策略互换)
动机 :在不改调用方的情况下切换算法/行为。
kotlin
class PostDiff: DiffUtil.ItemCallback<Post>() {
override fun areItemsTheSame(a: Post, b: Post) = a.id == b.id
override fun areContentsTheSame(a: Post, b: Post) = a == b
}
val adapter = ListAdapter(PostDiff()) { /* ... */ }
8) Adapter(适配器)
落点:RecyclerView.Adapter / PagingDataAdapter
动机 :把任意数据源适配到统一的 ViewHolder 渲染接口。
kotlin
class PostAdapter : ListAdapter<Post, VH>(PostDiff()) {
override fun onCreateViewHolder(p: ViewGroup, t: Int) = VH(ItemPostBinding.inflate(...))
override fun onBindViewHolder(h: VH, pos: Int) = h.bind(getItem(pos))
}
9) Decorator(装饰)
落点:RecyclerView.ItemDecoration / Insetter / WindowInsets 处理
动机 :在不修改原组件的前提下叠加行为/样式。
kotlin
recyclerView.addItemDecoration(object: RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, v: View, p: RecyclerView, s: State) {
outRect.bottom = 8.dp
}
})
10) Chain of Responsibility(责任链)
落点:OnBackPressedDispatcher、NestedScrolling 的 pre/post 链、WorkManager.beginWith().then() 链式任务
动机 :把请求沿链路传递,遇到能处理者即停止。
scss
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
// 优先级高者先拦截返回键
if (drawer.isOpen) drawer.close() else remove() /* 放行给下一个 */
}
11) Command(命令)
落点:WorkRequest(可序列化命令交给系统后台执行)、NavController.navigate(directions)
动机:把"要做的事"封装为对象,延迟/队列化执行。
kotlin
class UploadWorker(ctx: Context, params: WorkerParameters): CoroutineWorker(ctx, params) {
override suspend fun doWork(): Result { /* 真正的命令执行体 */ return Result.success() }
}
12) State(状态)
落点 A:SavedStateHandle、ViewModel 状态持有
落点 B:Compose 的 remember{} / rememberSaveable{} / "状态提升(state hoisting)"
动机:用不可变 UIState + 单一真相来源(SSOT)驱动 UI。
kotlin
@HiltViewModel
class HomeVM @Inject constructor(private val saved: SavedStateHandle): ViewModel() {
private val _ui = MutableStateFlow(UiState())
val ui: StateFlow<UiState> = _ui.asStateFlow()
}
@Composable
fun Home(vm: HomeVM = hiltViewModel()) {
val ui by vm.ui.collectAsState()
Screen(ui) // 纯函数式 UI
}
13) Template Method(模板方法)
落点:DefaultLifecycleObserver / Fragment 生命周期
动机 :父类/框架定义固定流程 ,子类覆盖具体步骤。
kotlin
class LogsObserver: DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) { /* 模版流程中的一步 */ }
}
lifecycle.addObserver(LogsObserver())
14) Facade(外观)
落点:NavController(对 Fragment 事务的门面)、WorkManager(对 JobScheduler/AlarmManager+Service 的门面)
动机 :用统一 API 屏蔽平台差异与复杂实现。
scss
findNavController().navigate(
HomeFragmentDirections.actionHomeToDetail(id = 42) // Safe Args + 单一入口
)
15) Iterator(迭代器)
落点:PagingSource → Pager → Flow<PagingData>
动机:按需迭代加载数据,UI 只"拉取下一页"。
kotlin
class PostSource(private val api: Api): PagingSource<Int, Post>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Post> {
val page = params.key ?: 1
val data = api.list(page)
return LoadResult.Page(data, prevKey = page-1, nextKey = page+1)
}
}
val flow = Pager(PagingConfig(pageSize = 20)) { PostSource(api) }.flow
组合范式:把模式拼起来
- MVVM(不是 GoF,但工程架构范式) :State(Compose/LiveData/Flow) + Observer + Repository + Factory(VM 创建)+(可选)Mediator(聚合/分页中枢)。
- 列表页面:Adapter + Strategy(DiffUtil) + Decorator(ItemDecoration) + Iterator(Paging)。
- 导航与后台任务:Facade(NavController/WorkManager) + Command(WorkRequest) + Chain(OnBackPressed/NestedScroll)。
实战要点与坑位
- LiveData vs Flow :UI 端想省事选 LiveData;想要背压/并发/算子选 Flow,配 repeatOnLifecycle。
- DiffUtil 的代价 :大对象请提供稳定 id 与高效 equals,必要时用 AsyncDifferConfig + 自定义线程池。
- Repository 划分:按业务边界而非技术边界拆分(如 UserRepo、FeedRepo),接口化便于测试。
- WorkManager 设计 :可重试任务要区分幂等 与幂等化输入(inputData + 去重 Key);链式 then = 责任链。
- Navigation:深链/多 back stack 用 navigation-ui-ktx + BottomNavigationView 的 setupWithNavController,避免自己手搓事务。
- Compose 的 State:坚持"状态提升"与不可变 data class,副作用放入 LaunchedEffect/DisposableEffect,不要在 Composable 里保业务单例。
一页速记(面试可背)
-
观察者:LiveData/Flow 监听 + 生命周期安全。
-
中介者:MediatorLiveData 聚合;Paging 的 RemoteMediator 协调网/库。
-
仓库:抽象数据来源,UI 只调仓库。
-
工厂:ViewModelProvider.Factory / SavedStateFactory。
-
单例:Room DB / Retrofit / DataStore。
-
生成器:WorkRequest/Constraints/导航 DSL。
-
策略:DiffUtil、LayoutManager 可替换。
-
适配器:RecyclerView.Adapter / PagingDataAdapter。
-
装饰:ItemDecoration/Insets。
-
责任链:OnBackPressed/NestedScroll/Work 链。
-
命令:WorkRequest、NavDirections。
-
状态:SavedStateHandle、Compose state。
-
模板方法:Lifecycle 回调骨架。
-
外观:NavController、WorkManager。
-
迭代器:PagingSource → PagingData。