一句话总结:
工厂模式就像「奶茶店点单」—— 你告诉店员要什么(参数),店员(工厂)根据需求调配原料(创建对象),Android 里的 BitmapFactory、LayoutInflater 都在用这套流水线!
一、工厂模式在 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 体系 | 主题切换、多配置适配 |
使用建议
- 简单工厂:适合工具类方法(如
BitmapFactory.decodeXX()) - 工厂方法:适合 SDK 设计(允许用户自定义实现,如
LayoutInflater.Factory) - 抽象工厂:适合全局配置管理(如换肤、多语言)
注意事项
- 避免过度设计:不是所有创建逻辑都需要工厂模式
- 优先使用接口:
Resources依赖ResourcesImpl接口而非具体类 - 结合单例模式:工厂类通常设计为单例(如
BitmapFactory全是静态方法)
口诀总结:
「对象创建太复杂,工厂模式来封装
简单工厂参数判,工厂方法子类忙
抽象工厂产家族,Resources 是榜样」