一句话说透Android里面的装饰器模式

175 阅读3分钟

一句话总结:
装饰器模式就像「给手机装保护壳」—— 不拆原机,动态增强功能,Android 里的 ContextWrapperJava IO流 都靠它灵活升级!


一、装饰器模式在 Android 的经典案例

核心思想:通过包装(Wrapper)  动态扩展对象功能,不修改原类代码,避免继承导致的类爆炸。

1. Context 体系的装饰器结构

// 组件接口:Context(被装饰对象的抽象)  
public abstract class Context {  
    public abstract void startActivity(Intent intent);  
    public abstract Object getSystemService(String name);  
}  

// 具体组件:ContextImpl(实际干活的小弟)  
class ContextImpl extends Context {  
    @Override  
    public void startActivity(Intent intent) {  
        // 真正启动 Activity 的逻辑(通过 AMS)  
    }  
}  

// 装饰器基类:ContextWrapper(持有一个 Context 引用)  
public class ContextWrapper extends Context {  
    protected Context mBase; // 被装饰对象  

    public ContextWrapper(Context base) {  
        mBase = base;  
    }  

    @Override  
    public void startActivity(Intent intent) {  
        mBase.startActivity(intent); // 委托给实际 Context  
    }  
}  

// 具体装饰器:ContextThemeWrapper(增加主题功能)  
public class ContextThemeWrapper extends ContextWrapper {  
    private Resources.Theme mTheme;  

    @Override  
    public void setTheme(int resid) {  
        mTheme = resources.newTheme(); // 添加主题处理逻辑  
    }  
}  

// 最终使用:Activity 继承自 ContextThemeWrapper  
public class Activity extends ContextThemeWrapper {  
    // Activity 本身也是一个装饰器!  
}  

装饰链
ContextImpl → ContextWrapper → ContextThemeWrapper → Activity
每层装饰添加新功能(如主题、生命周期管理),层层增强


二、源码级工作原理分析

1. 创建 Activity 时的装饰过程

当启动 Activity 时,系统通过以下步骤构建 Context 装饰链:

// 创建 ContextImpl(具体组件)  
ContextImpl contextImpl = new ContextImpl(...);  

// 用 ContextWrapper 包装  
ContextWrapper contextWrapper = new ContextWrapper(contextImpl);  

// 继续用 ContextThemeWrapper 装饰  
ContextThemeWrapper themeWrapper = new ContextThemeWrapper(contextWrapper);  

// 最终 Activity 持有装饰后的 Context  
class MainActivity extends Activity {  
    // 实际使用的是被多层装饰后的 Context  
}  

2. 方法调用流程(以 startActivity 为例)

Activity.startActivity() →  
ContextThemeWrapper.startActivity() →  
ContextWrapper.startActivity() →  
ContextImpl.startActivity()  
  • 透明增强:Activity 无需知道底层如何启动,只管调用
  • 功能扩展:中间层可插入额外逻辑(如权限检查)

三、装饰器 vs 继承 vs 代理模式

维度装饰器模式继承代理模式
核心目标动态增强功能静态扩展功能控制对象访问
关系组合 + 相同接口父子类关系相同接口
灵活性高(运行时动态组合)低(编译时确定)
Android案例ContextWrapper → ContextImpl自定义 View 继承系统 ViewActivityManagerProxy

四、装饰器模式的优缺点

优点

  1. 灵活扩展:动态添加功能,无需修改原类(如给 Context 加主题)
  2. 避免类爆炸:替代多层次的继承(如 ContextWrapper 仅 600 行代码,支撑整个 Activity 体系)
  3. 符合开闭原则:扩展开放,修改关闭

缺点

  1. 多层装饰难调试:调用链过长时定位问题困难
  2. 设计复杂度高:需设计大量小类(如 ContextThemeWrapperTintContextWrapper

五、实际开发场景建议

适用场景

  1. 动态增强系统类功能(如给 InputStream 加缓冲)
  2. 避免污染原有代码(如第三方 SDK 的功能扩展)
  3. 组合替代继承(如 UI 组件功能定制)

不适用场景

  1. 功能变化少:直接继承更简单
  2. 需要彻底重写方法:装饰器模式不适合完全改变行为

六、总结口诀

装饰模式像套娃,层层包装功能加
Context 体系是典范,Java IO 也靠它
若要扩展不改码,组合替代继承法