一句话说透Android里面的门面模式

190 阅读4分钟

一句话总结:
门面模式就像「酒店前台」—— 一个窗口搞定所有复杂操作,Android 里的 ContextGlide 都靠它隐藏底层巨兽,让开发者轻松调用!


一、门面模式的核心思想

核心作用简化入口,把复杂的子系统调用封装成一个干净利落的 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)处理实际逻辑  

门面作用

  • 隐藏了 InstrumentationActivityTaskManagerBinder 等底层交互
  • 开发者只需关注 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

五、门面模式的优缺点与使用场景

优点

  1. 降低使用复杂度:把几十个类的交互简化为一个方法调用
  2. 提高可维护性:修改子系统不影响客户端代码(如 Glide 4 → Glide 5)
  3. 减少依赖:客户端只需依赖门面类,不直接接触子系统

缺点

  1. 过度封装风险:门面类可能变成“上帝类”(如 Context 有 500+ 方法)
  2. 灵活性下降:需要定制化功能时,可能得绕开门面直接操作子系统

使用场景

  1. SDK 设计(如 Glide、Retrofit)
  2. 复杂模块封装(如网络层、数据库层)
  3. 系统服务调用(如 Activity 启动、广播发送)

六、实际开发建议

该做的

  1. 为复杂模块设计门面类:比如封装网络请求为 HttpFacade.get(url).parseJson()
  2. 保持门面类精简:超过 20 个方法就该考虑拆分
  3. 结合单例模式:确保门面类容易访问(如 Glide.with()

不该做的

  1. 在门面类里写业务逻辑(它应该只做转发和封装)
  2. 暴露子系统细节(如把 Binder 对象直接返回给客户端)
  3. 滥用门面导致过度设计(简单模块不需要门面)

七、总结口诀

门面模式像前台,复杂操作一招解
Context 和 Glide,隐藏巨兽显简洁
若要封装复杂库,门面一出手,代码更和谐