一句话说透Android里面的工厂模式

232 阅读4分钟

一句话总结:
工厂模式就像「奶茶店点单」—— 你告诉店员要什么(参数),店员(工厂)根据需求调配原料(创建对象),Android 里的 BitmapFactoryLayoutInflater 都在用这套流水线!


一、工厂模式在 Android 的三种形态

1. 简单工厂模式(Static Factory)—— 快餐店菜单

特点:一个工厂类搞定所有对象创建,根据参数返回不同类型对象
源码案例BitmapFactory

// frameworks/base/graphics/java/android/graphics/BitmapFactory.java  
public static Bitmap decodeFile(String pathName) {  
    return decodeFile(pathName, null);  
}  

public static Bitmap decodeResource(Resources res, int id) {  
    return decodeResource(res, id, null);  
}  

// 实际创建 Bitmap 的 native 方法  
private static native Bitmap nativeDecodeFile(String pathName);  

底层原理

  • 根据输入类型(文件路径、资源 ID、流等)调用不同的 nativeDecodeXXX 方法
  • 隐藏了不同图片格式(JPEG、PNG、WebP)的解码细节

适用场景

  • 创建逻辑简单,类型有限
  • 不需要频繁扩展新类型

2. 工厂方法模式(Factory Method)—— 加盟店自主创新

特点定义抽象工厂接口,让子类决定具体实现
源码案例LayoutInflater 的 onCreateView

// frameworks/base/core/java/android/view/LayoutInflater.java  
public abstract class LayoutInflater {  
    // 工厂方法抽象定义  
    protected abstract View onCreateView(String name, AttributeSet attrs);  

    // 实际创建 View 的流程  
    public View createView(String name, String prefix, AttributeSet attrs) {  
        // 优先尝试通过 Factory2 创建(如 AppCompat 替换系统控件)  
        View view = mFactory2.onCreateView(parent, name, context, attrs);  
        if (view != null) return view;  

        // 反射创建 View 实例  
        Class<? extends View> clazz = mClassLoader.loadClass(name).asSubclass(View.class);  
        Constructor<? extends View> constructor = clazz.getConstructor(mConstructorSignature);  
        return constructor.newInstance(args);  
    }  
}  

// Activity 中可设置自定义 Factory  
getLayoutInflater().setFactory2(new LayoutInflater.Factory2() {  
    @Override  
    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {  
        // 自定义 View 创建逻辑(如全局替换 TextView)  
        if ("TextView".equals(name)) {  
            return new CustomTextView(context, attrs);  
        }  
        return null; // 返回 null 则走系统默认逻辑  
    }  
});  

底层设计亮点

  • 支持通过 Factory2 动态替换 View 类型(AppCompat 兼容库的核心机制)
  • 使用反射 + 缓存提升创建效率(mConstructorMap 缓存构造函数)

3. 抽象工厂模式(Abstract Factory)—— 中央厨房供应链

特点:生产相关联的产品家族(如不同主题的按钮、文本框)
源码案例Resources 体系

// frameworks/base/core/java/android/content/res/Resources.java  
public class Resources {  
    // 创建 Drawable 的工厂方法  
    public Drawable getDrawable(int id) throws NotFoundException {  
        return getDrawable(id, getTheme());  
    }  

    // 实际委托给 ResourcesImpl  
    @Override  
    public Drawable getDrawable(int id, @Nullable Theme theme) {  
        return mResourcesImpl.loadDrawable(this, id, theme);  
    }  
}  

// 不同配置对应不同资源工厂  
public class ResourcesImpl {  
    Drawable loadDrawable(Resources wrapper, int id, Theme theme) {  
        // 根据设备配置(分辨率、语言等)加载不同资源  
        final TypedValue value = obtainTempTypedValue();  
        getValue(id, value, true);  
        return loadDrawable(wrapper, value, id, theme, true);  
    }  
}  

核心逻辑

  • 根据设备配置(屏幕密度、语言等)自动选择资源
  • 不同 ResourcesImpl 生产匹配当前环境的资源家族(如图片、字符串、布局)

二、工厂模式的底层设计优势

1. 隔离变化点

  • Bitmap 解码器变更:新增 WebP 格式只需加 nativeDecodeWebP(),无需修改调用方
  • View 创建逻辑:AppCompat 通过自定义 Factory2 替换系统控件,无需改 setContentView()

2. 集中管理对象创建

  • 性能优化LayoutInflater 缓存构造函数(mConstructorMap),避免重复反射
  • 内存控制BitmapFactory 统一处理 OOM 和尺寸缩放

3. 依赖抽象而非实现

  • 资源加载Resources 不关心 ResourcesImpl 的具体实现(可以是本地资源或动态加载)
  • 主题切换:通过更换 Resources 实例实现全局换肤

三、工厂模式在开源框架中的应用

1. Retrofit 的 Converter.Factory

// 根据接口方法返回类型选择数据转换器  
public interface Converter<F, T> {  
    T convert(F value);  
}  

// 工厂方法设计  
public abstract class Converter.Factory {  
    // 根据类型和注解创建转换器  
    public @Nullable Converter<ResponseBody, ?> responseBodyConverter(  
        Type type, Annotation[] annotations, Retrofit retrofit) {  
        return null;  
    }  
}  

// 使用示例:添加 Gson 转换器  
Retrofit retrofit = new Retrofit.Builder()  
    .addConverterFactory(GsonConverterFactory.create())  
    .build();  

2. Glide 的 ModelLoaderFactory

// 根据数据模型类型(URL、File 等)创建对应的加载器  
public interface ModelLoaderFactory<T, Data> {  
    ModelLoader<T, Data> build(MultiModelLoaderFactory multiFactory);  
}  

// 注册网络加载工厂  
Glide.get(context).registry.append(  
    String.class, InputStream.class, new UrlLoader.Factory());  

四、总结与最佳实践

三种工厂模式对比

模式特点Android 案例适用场景
简单工厂一个工厂类处理所有类型BitmapFactory类型少且稳定的场景
工厂方法子类决定具体实现LayoutInflater需要灵活扩展的框架设计
抽象工厂生产关联产品家族Resources 体系主题切换、多配置适配

使用建议

  1. 简单工厂:适合工具类方法(如 BitmapFactory.decodeXX()
  2. 工厂方法:适合 SDK 设计(允许用户自定义实现,如 LayoutInflater.Factory
  3. 抽象工厂:适合全局配置管理(如换肤、多语言)

注意事项

  1. 避免过度设计:不是所有创建逻辑都需要工厂模式
  2. 优先使用接口:Resources 依赖 ResourcesImpl 接口而非具体类
  3. 结合单例模式:工厂类通常设计为单例(如 BitmapFactory 全是静态方法)

口诀总结
对象创建太复杂,工厂模式来封装
简单工厂参数判,工厂方法子类忙
抽象工厂产家族,Resources 是榜样