一句话总结:
门面模式就像「酒店前台」—— 一个窗口搞定所有复杂操作,Android 里的 Context、Glide 都靠它隐藏底层巨兽,让开发者轻松调用!
一、门面模式的核心思想
核心作用:简化入口,把复杂的子系统调用封装成一个干净利落的 API
类比场景:
- 子系统:酒店后厨、保洁、客房服务
- 门面:酒店前台
- 用户:开发者
效果:用户只需说「我要入住」,无需知道房间怎么打扫、床单怎么更换
二、Android 源码中的门面模式案例
1. Context 类:系统服务的万能入口
源码结构:
// frameworks/base/core/java/android/content/Context.java
public abstract class Context {
// 门面方法 1:启动 Activity(隐藏了 AMS 交互细节)
public abstract void startActivity(Intent intent);
// 门面方法 2:获取系统服务(隐藏了 ServiceManager 查询逻辑)
public abstract Object getSystemService(String name);
// 门面方法 3:访问资源(隐藏了 Resources 加载机制)
public abstract Resources getResources();
}
// 实际实现类 ContextImpl
class ContextImpl extends Context {
@Override
public void startActivity(Intent intent) {
// 内部调用 ActivityTaskManagerService(跨进程 Binder 调用)
mMainThread.getActivityTaskManager().startActivity(...);
}
@Override
public Object getSystemService(String name) {
// 从 ServiceManager 查询并返回 Binder 代理对象
return SystemServiceRegistry.getSystemService(this, name);
}
}
门面价值:
- 开发者调用
context.startActivity()即可启动页面,不用写一堆ActivityTaskManager.getService().startActivity(...) - 统一处理权限检查、进程通信等细节
2. Glide:图片加载的一站式服务
门面设计:
// 门面入口:Glide.with()
public class Glide {
// 隐藏了 RequestManagerRetriever、Engine、Registry 等复杂子系统
public static RequestManager with(Activity activity) {
return getRetriever(activity).get(activity);
}
private static RequestManagerRetriever getRetriever(Context context) {
// 初始化线程池、缓存、解码器等模块
return Glide.get(context).getRequestManagerRetriever();
}
}
// 使用方式(干净利落的三板斧)
Glide.with(context)
.load("http://xxx/image.jpg")
.into(imageView);
底层复杂度:
- 子系统包括:
Engine(加载引擎)、DiskCache(磁盘缓存)、Registry(解码器注册) - 门面模式把这些模块的交互封装在
Glide类中
三、门面模式的底层实现原理
1. 封装跨进程调用(以 startActivity 为例)
调用链分析:
context.startActivity()
→ ContextImpl.startActivity()
→ Instrumentation.execStartActivity()
→ ActivityTaskManager.getService().startActivity() (Binder 跨进程调用)
→ ActivityTaskManagerService(ATMS)处理实际逻辑
门面作用:
- 隐藏了
Instrumentation、ActivityTaskManager、Binder等底层交互 - 开发者只需关注
Intent和页面跳转结果
2. 统一异常处理(以 getSystemService 为例)
源码片段:
// frameworks/base/core/java/android/app/SystemServiceRegistry.java
public static Object getSystemService(ContextImpl ctx, String name) {
// 门面内部处理各种异常和兼容性问题
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
if (fetcher == null) {
if (!sEnableServiceNotFoundWtf) {
return null;
}
throw new IllegalArgumentException(...);
}
return fetcher.getService(ctx);
}
门面价值:
- 统一处理服务不存在、版本不兼容等错误
- 对开发者透明,无需写一堆
try-catch
四、门面模式 vs 其他模式
| 模式 | 核心区别 | Android 案例 |
|---|---|---|
| 门面模式 | 简化复杂系统调用,提供统一入口 | Context、Glide |
| 适配器模式 | 解决接口不兼容问题 | RecyclerView.Adapter |
| 代理模式 | 控制对象访问,可能添加额外逻辑 | ActivityManagerProxy |
五、门面模式的优缺点与使用场景
优点:
- 降低使用复杂度:把几十个类的交互简化为一个方法调用
- 提高可维护性:修改子系统不影响客户端代码(如 Glide 4 → Glide 5)
- 减少依赖:客户端只需依赖门面类,不直接接触子系统
缺点:
- 过度封装风险:门面类可能变成“上帝类”(如
Context有 500+ 方法) - 灵活性下降:需要定制化功能时,可能得绕开门面直接操作子系统
使用场景:
- SDK 设计(如 Glide、Retrofit)
- 复杂模块封装(如网络层、数据库层)
- 系统服务调用(如 Activity 启动、广播发送)
六、实际开发建议
该做的:
- 为复杂模块设计门面类:比如封装网络请求为
HttpFacade.get(url).parseJson() - 保持门面类精简:超过 20 个方法就该考虑拆分
- 结合单例模式:确保门面类容易访问(如
Glide.with())
不该做的:
- 在门面类里写业务逻辑(它应该只做转发和封装)
- 暴露子系统细节(如把
Binder对象直接返回给客户端) - 滥用门面导致过度设计(简单模块不需要门面)
七、总结口诀
「门面模式像前台,复杂操作一招解
Context 和 Glide,隐藏巨兽显简洁
若要封装复杂库,门面一出手,代码更和谐」