安卓开发设计模式全解析
一、设计模式概述
设计模式是解决特定场景下软件设计问题的可复用方案,由 GoF(四人组)在《设计模式:可复用面向对象软件的基础》中归纳为 23 种,核心价值在于:
-
提高代码复用性:避免重复造轮子
-
增强可维护性:代码结构清晰,便于修改
-
提升扩展性:应对需求变更时更灵活
-
降低复杂度:将复杂问题拆解为标准化模块
在安卓开发中,设计模式贯穿于 Framework(如Context
、RecyclerView
)、第三方库(如 Retrofit、Glide)及业务代码。
按功能可将设计模式分为三类:
类型 | 核心作用 | 安卓常用模式 |
---|---|---|
创建型模式 | 管理对象创建,隐藏创建细节 | 单例、工厂、建造者、原型 |
结构型模式 | 优化类 / 对象组合,简化结构 | 适配器、装饰者、代理、外观 |
行为型模式 | 定义对象通信与职责分配 | 观察者、策略、命令、迭代器 |
二、创建型设计模式(5 种)
1. 单例模式(Singleton)
定义
确保一个类仅有一个实例,并提供全局唯一访问入口。
核心场景(安卓)
-
全局状态管理(如用户信息、配置信息)
-
资源密集型对象(如网络请求客户端、数据库连接)
-
Framework 中的
Application
类(本质是系统维护的单例)
实现方式与代码示例
(1)饿汉式(线程安全,加载时初始化)
java
// 网络请求管理单例(饿汉式)
public class NetworkManager {
// 类加载时直接初始化实例(JVM保证线程安全)
private static final NetworkManager INSTANCE = new NetworkManager();
// 私有构造:禁止外部new
private NetworkManager() {
// 初始化 Retrofit/OkHttp 等
}
// 全局访问入口
public static NetworkManager getInstance() {
return INSTANCE;
}
// 业务方法:发起网络请求
public void request(String url, Callback callback) {
// 实现请求逻辑
}
}
优点 :简单高效,无线程安全问题;缺点:类加载时就初始化,若实例未被使用会浪费内存(如 APP 启动时加载但后续未用)。
(2)懒汉式(双重检查锁,按需初始化)
java
// 网络请求管理单例(双重检查锁)
public class NetworkManager {
// volatile:禁止指令重排,确保实例初始化完成后再被访问
private static volatile NetworkManager INSTANCE;
private NetworkManager() {}
public static NetworkManager getInstance() {
// 第一次检查:避免已初始化时的锁竞争
if (INSTANCE == null) {
// 加锁:确保多线程下仅一个线程进入初始化
synchronized (NetworkManager.class) {
// 第二次检查:防止多线程同时进入第一个if后重复初始化
if (INSTANCE == null) {
INSTANCE = new NetworkManager();
}
}
}
return INSTANCE;
}
}
优点 :按需初始化,节省内存;缺点 :实现复杂,需注意volatile
关键字(否则可能出现 "半初始化实例" 问题)。
(3)静态内部类(推荐,兼顾安全与效率)
java
// 网络请求管理单例(静态内部类)
public class NetworkManager {
private NetworkManager() {}
// 静态内部类:JVM加载外部类时不会初始化内部类
private static class SingletonHolder {
private static final NetworkManager INSTANCE = new NetworkManager();
}
// 调用getInstance时才加载内部类,初始化实例(线程安全)
public static NetworkManager getInstance() {
return SingletonHolder.INSTANCE;
}
}
优点 :按需初始化、线程安全(JVM 保证)、实现简单;缺点 :无法传参初始化(如需传Context
需额外调用init
方法)。
(4)枚举单例(防反射 / 序列化破坏)
java
typescript
// 枚举单例(最安全,推荐用于关键场景)
public enum NetworkManager {
INSTANCE;
// 初始化方法
public void init(Context context) {
// 初始化逻辑(如传入Application Context)
}
// 业务方法
public void request(String url, Callback callback) {
// 实现逻辑
}
}
// 使用方式
NetworkManager.INSTANCE.init(getApplicationContext());
NetworkManager.INSTANCE.request("https://api.example.com", callback);
优点 :天然防反射(枚举构造器由 JVM 控制,无法通过反射调用)、防序列化(枚举的readObject
方法会返回原实例);缺点:枚举类占用内存略高(安卓中影响可忽略),无法延迟初始化。
安卓注意事项
-
避免持有
Activity/Fragment
的Context
:会导致内存泄漏,应使用Application Context
-
多进程场景慎用:多进程会创建多个虚拟机,单例实例不共享(需用
ContentProvider
或SP
跨进程同步)
2. 工厂模式(Factory)
定义
定义一个创建对象的接口,但由子类决定实例化哪个类,将创建逻辑与使用逻辑分离。
分类与安卓场景
类型 | 核心逻辑 | 安卓应用场景 |
---|---|---|
简单工厂 | 一个工厂类创建所有对象 | Retrofit 创建 Service 接口 |
工厂方法 | 每个产品对应一个工厂子类 | 自定义 View 工厂(如多主题 View) |
抽象工厂 | 工厂创建 "产品族"(多个相关产品) | 多平台适配(如 Android/iOS 控件工厂) |
代码示例:Retrofit 中的简单工厂
Retrofit 通过create
方法隐藏Service
接口的实现细节(动态代理生成实现类),本质是简单工厂模式:
java
// 1. 定义产品接口(Service)
public interface ApiService {
@GET("user")
Call<User> getUser(@Query("id") String userId);
}
// 2. 工厂类(Retrofit)创建产品实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
// 工厂方法:create() 生成 ApiService 实例(无需关心实现)
ApiService apiService = retrofit.create(ApiService.class);
// 3. 使用产品(调用接口)
apiService.getUser("123").enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {}
@Override
public void onFailure(Call<User> call, Throwable t) {}
});
优点与缺点
-
优点:解耦创建与使用、便于扩展(新增产品只需修改工厂,无需修改调用方)
-
缺点:简单工厂违背 "开闭原则"(新增产品需修改工厂类);工厂方法会增加类数量(产品越多,工厂类越多)
3. 建造者模式(Builder)
定义
将复杂对象的构建过程与表示分离,使得同一构建过程可以创建不同的表示(链式调用是典型特征)。
安卓核心场景
-
复杂对象创建(如
AlertDialog
、OkHttp Request
) -
第三方库(Glide、Retrofit Builder、Room Database)
代码示例 1:原生 AlertDialog.Builder
java
// 建造者模式创建AlertDialog
new AlertDialog.Builder(this)
.setTitle("提示") // 设置标题(建造者方法)
.setMessage("确定要删除吗?") // 设置内容(建造者方法)
.setPositiveButton("确定", (dialog, which) -> {
// 确定逻辑
})
.setNegativeButton("取消", null)
.create() // 构建Dialog实例
.show(); // 展示Dialog
代码示例 2:自定义建造者(User 对象)
java
// 复杂对象:User(包含多个可选属性)
public class User {
private final String id; // 必选属性
private final String name; // 必选属性
private final int age; // 可选属性
private final String phone; // 可选属性
private final String email; // 可选属性
// 私有构造:仅允许Builder调用
private User(Builder builder) {
this.id = builder.id;
this.name = builder.name;
this.age = builder.age;
this.phone = builder.phone;
this.email = builder.email;
}
// 建造者类(静态内部类)
public static class Builder {
// 必选属性(初始化时传入)
private final String id;
private final String name;
// 可选属性(默认值)
private int age = 0;
private String phone = "";
private String email = "";
// 必选属性构造
public Builder(String id, String name) {
this.id = id;
this.name = name;
}
// 可选属性设置(返回Builder自身,支持链式调用)
public Builder setAge(int age) {
this.age = age;
return this;
}
public Builder setPhone(String phone) {
this.phone = phone;
return this;
}
public Builder setEmail(String email) {
this.email = email;
return this;
}
// 构建User实例
public User build() {
// 可在这里添加参数校验(如id不能为空)
if (TextUtils.isEmpty(id)) {
throw new IllegalArgumentException("id不能为空");
}
return new User(this);
}
}
}
// 使用方式(链式调用,清晰易读)
User user = new User.Builder("123", "张三")
.setAge(25)
.setPhone("13800138000")
.build();
优点与缺点
-
优点:参数设置清晰(链式调用)、支持参数校验、避免 "telescoping constructor"(多参数构造器)
-
缺点:增加类数量(需额外定义 Builder)、构建过程略复杂(需手动实现 Builder 逻辑)
4. 原型模式(Prototype)
定义
通过复制现有对象来创建新对象,无需重新初始化(适合创建成本高的对象)。
安卓核心场景
-
Intent
的clone()
方法(复制 Intent 实例,避免重新设置参数) -
RecyclerView
的ViewHolder
缓存(复用已有 ViewHolder,减少创建开销) -
复杂对象复制(如配置信息、列表数据)
代码示例:Intent 克隆
java
// 原Intent:携带大量参数
Intent originalIntent = new Intent(this, TargetActivity.class);
originalIntent.putExtra("user_id", "123");
originalIntent.putExtra("user_info", new User("123", "张三"));
originalIntent.putExtra("is_login", true);
// 克隆Intent(浅克隆)
Intent clonedIntent = (Intent) originalIntent.clone();
// 修改克隆Intent的参数(不影响原Intent)
clonedIntent.putExtra("is_login", false);
// 启动Activity
startActivity(clonedIntent);
关键概念:浅克隆 vs 深克隆
-
浅克隆 :仅复制对象本身,引用类型属性仍指向原对象(如
Intent.clone()
、ArrayList.clone()
) -
深克隆:复制对象及所有引用类型属性(需手动实现,如通过序列化 / 反序列化)
优点与缺点
-
优点:减少对象创建成本(尤其复杂对象)、简化创建逻辑
-
缺点:浅克隆可能导致引用共享问题;深克隆实现复杂(需处理所有引用类型)
三、结构型设计模式(4 种)
1. 适配器模式(Adapter)
定义
将一个类的接口转换成客户端期望的另一个接口,使原本因接口不兼容而无法工作的类可以协同工作。
安卓核心场景
-
RecyclerView.Adapter
(将数据适配为ViewHolder
,供RecyclerView
展示) -
ViewPager.Adapter
(将页面数据适配为View
,供ViewPager
切换) -
BroadcastReceiver
(将系统 / 应用广播适配为自定义逻辑)
代码示例:RecyclerView.Adapter(最典型)
java
// 1. 目标接口:RecyclerView需要的Adapter接口(系统定义)
public abstract class RecyclerView.Adapter<VH extends RecyclerView.ViewHolder> {
public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
public abstract void onBindViewHolder(VH holder, int position);
public abstract int getItemCount();
}
// 2. 适配者:业务数据(如User列表)
List<User> userList = Arrays.asList(
new User("1", "张三"),
new User("2", "李四")
);
// 3. 适配器:将User列表适配为RecyclerView可识别的ViewHolder
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHolder> {
private List<User> mUserList;
public UserAdapter(List<User> userList) {
this.mUserList = userList;
}
// 创建ViewHolder(视图容器)
@Override
public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_user, parent, false);
return new UserViewHolder(itemView);
}
// 绑定数据(将User数据适配到ViewHolder)
@Override
public void onBindViewHolder(UserViewHolder holder, int position) {
User user = mUserList.get(position);
holder.tvName.setText(user.getName());
holder.tvId.setText(user.getId());
}
// 数据数量
@Override
public int getItemCount() {
return mUserList.size();
}
// 视图容器(ViewHolder)
public static class UserViewHolder extends RecyclerView.ViewHolder {
TextView tvId;
TextView tvName;
public UserViewHolder(View itemView) {
super(itemView);
tvId = itemView.findViewById(R.id.tv_id);
tvName = itemView.findViewById(R.id.tv_name);
}
}
}
// 4. 使用适配器
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(new UserAdapter(userList));
优点与缺点
-
优点:解耦接口与实现、复用现有类(无需修改原类即可适配新接口)
-
缺点:增加适配层,可能导致代码复杂度上升;过多适配器可能影响性能
2. 装饰者模式(Decorator)
定义
动态地给一个对象添加额外功能,同时不改变其原有的结构(比继承更灵活)。
安卓核心场景
-
Context
家族(ContextWrapper
装饰ContextImpl
,添加 Activity/Service 功能) -
IO 流(如
BufferedReader
装饰FileReader
,添加缓冲功能) -
Glide 图片加载(添加圆角、模糊等效果,不修改原加载逻辑)
代码示例:Context 的装饰者模式
Context
是抽象接口,ContextImpl
是具体实现(负责 Context 的核心功能),ContextWrapper
是装饰者(持有Context
引用,添加额外功能):
java
// 1. 抽象组件:Context(定义核心功能接口)
public abstract class Context {
public abstract void startActivity(Intent intent);
public abstract void sendBroadcast(Intent intent);
// 其他核心方法...
}
// 2. 具体组件:ContextImpl(实现Context的核心功能)
class ContextImpl extends Context {
@Override
public void startActivity(Intent intent) {
// 实现启动Activity的底层逻辑
}
@Override
public void sendBroadcast(Intent intent) {
// 实现发送广播的底层逻辑
}
}
// 3. 装饰者:ContextWrapper(持有Context引用,添加额外功能)
public class ContextWrapper extends Context {
Context mBase; // 持有被装饰的Context实例
public ContextWrapper(Context base) {
mBase = base;
}
// 转发核心方法到被装饰者
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
@Override
public void sendBroadcast(Intent intent) {
mBase.sendBroadcast(intent);
}
}
// 4. 具体装饰者1:Activity(装饰Context,添加界面功能)
public class Activity extends ContextWrapper {
// 新增功能:管理Activity生命周期
public void onCreate(Bundle savedInstanceState) {
// 实现Activity创建逻辑
}
public void onDestroy() {
// 实现Activity销毁逻辑
}
}
// 5. 具体装饰者2:Service(装饰Context,添加后台功能)
public class Service extends ContextWrapper {
// 新增功能:管理Service生命周期
public void onStartCommand(Intent intent, int flags, int startId) {
// 实现Service启动逻辑
}
}
优点与缺点
-
优点:灵活扩展功能(无需修改原类)、支持多装饰(多层功能叠加)
-
缺点:增加类数量(装饰者与被装饰者分离)、调试难度上升(需跟踪装饰链)
3. 代理模式(Proxy)
定义
为其他对象提供一种代理以控制对该对象的访问(代理类与被代理类实现同一接口)。
安卓核心场景
-
Retrofit 动态代理(代理
Service
接口,生成网络请求实现) -
图片加载代理(如 Glide 的
RequestManager
,代理图片加载逻辑) -
权限代理(如动态权限申请,代理原功能的权限校验)
代码示例:Retrofit 动态代理
Retrofit 通过Proxy.newProxyInstance
生成Service
接口的代理对象,拦截方法调用并生成网络请求:
java
// 1. 被代理接口:ApiService
public interface ApiService {
@GET("user")
Call<User> getUser(@Query("id") String userId);
}
// 2. 动态代理生成代理对象(Retrofit内部逻辑简化)
public <T> T create(Class<T> service) {
return (T) Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[]{service},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1. 拦截方法调用,解析注解(如@GET、@Query)
GET getAnnotation = method.getAnnotation(GET.class);
String path = getAnnotation.value(); // 解析路径:"user"
// 2. 解析参数(如userId)
Query queryAnnotation = method.getParameterAnnotations()[0][0];
String paramName = queryAnnotation.value(); // 解析参数名:"id"
String paramValue = (String) args[0]; // 解析参数值:"123"
// 3. 生成Request(网络请求对象)
Request request = new Request.Builder()
.url("https://api.example.com/" + path + "?" + paramName + "=" + paramValue)
.build();
// 4. 返回Call对象(供调用方发起请求)
return new OkHttpCall(request);
}
}
);
}
// 3. 使用代理对象(调用方无需关心代理逻辑)
ApiService apiService = retrofit.create(ApiService.class);
apiService.getUser("123").enqueue(callback);
优点与缺点
-
优点:控制访问(如权限校验、缓存)、隐藏实现细节(如 Retrofit 代理网络请求逻辑)
-
缺点 :增加代理层,可能影响性能;动态代理实现复杂(需理解
InvocationHandler
)
4. 外观模式(Facade)
定义
为子系统中的一组接口提供一个统一的高层接口,使子系统更易于使用(简化复杂系统的调用)。
安卓核心场景
-
第三方 SDK 封装(如支付 SDK、推送 SDK,封装复杂接口为简单调用)
-
业务层封装(如 "用户登录" 功能,封装网络请求、数据存储、状态更新)
代码示例:支付 SDK 外观封装
假设支付 SDK 有多个复杂接口(如订单创建、支付签名、结果回调),通过外观类简化调用:
java
// 1. 子系统复杂接口(支付SDK内部接口)
class OrderService {
public String createOrder(String goodsId, float amount) {
// 复杂逻辑:创建订单,返回订单号
return "ORDER123456";
}
}
class PayService {
public String sign(String orderId, String userId) {
// 复杂逻辑:生成支付签名
return "SIGN_XXXXXX";
}
public void pay(String orderId, String sign, PayCallback callback) {
// 复杂逻辑:发起支付请求
callback.onPaySuccess(orderId);
}
}
class CallbackService {
public void registerCallback(PayCallback callback) {
// 复杂逻辑:注册支付结果回调
}
}
// 2. 外观类(统一接口,简化调用)
public class PayFacade {
private OrderService orderService;
private PayService payService;
private CallbackService callbackService;
// 初始化子系统
public PayFacade() {
orderService = new OrderService();
payService = new PayService();
callbackService = new CallbackService();
}
// 统一支付接口(封装所有子系统逻辑)
public void pay(String goodsId, float amount, String userId, PayCallback callback) {
// 1. 创建订单
String orderId = orderService.createOrder(goodsId, amount);
// 2. 生成签名
String sign = payService.sign(orderId, userId);
// 3. 注册回调
callbackService.registerCallback(callback);
// 4. 发起支付
payService.pay(orderId, sign, callback);
}
// 支付回调接口
public interface PayCallback {
void onPaySuccess(String orderId);
void onPayFailure(String orderId, String reason);
}
}
// 3. 使用外观类(无需关心子系统细节)
PayFacade payFacade = new PayFacade();
payFacade.pay(
"GOODS001", 99.9f, "USER123",
new PayFacade.PayCallback() {
@Override
public void onPaySuccess(String orderId) {
Toast.makeText(MainActivity.this, "支付成功:" + orderId, Toast.LENGTH_SHORT).show();
}
@Override
public void onPayFailure(String orderId, String reason) {
Toast.makeText(MainActivity.this, "支付失败:" + reason, Toast.LENGTH\_SHORT).show();
}
}
);
优点与缺点
-
优点:简化调用(隐藏子系统复杂度)、降低耦合(调用方与子系统解耦)
-
缺点:外观类可能成为 "上帝类"(职责过多);子系统扩展时可能需要修改外观类
四、行为型设计模式(4 种)
1. 观察者模式(Observer)
定义
定义对象间的一对多依赖关系,当一个对象(被观察者)状态改变时,所有依赖它的对象(观察者)都会收到通知并自动更新。
安卓核心场景
-
LiveData
(观察数据变化,自动更新 UI,感知生命周期) -
EventBus/RxJava
(事件订阅 - 发布,解耦组件通信) -
BroadcastReceiver
(系统 / 应用事件通知) -
DataBinding
(数据变化自动更新 UI)
代码示例:LiveData 的观察者模式
java
// 1. 被观察者:LiveData(系统实现,感知生命周期)
private MutableLiveData\<User> mUserLiveData = new MutableLiveData<>();
// 2. 观察者:Activity/Fragment(实现Observer接口)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 观察LiveData(this为LifecycleOwner,自动绑定生命周期)
mUserLiveData.observe(this, new Observer<User>() {
@Override
public void onChanged(User user) {
// 数据变化时更新UI(自动在主线程执行)
tvName.setText(user.getName());
tvAge.setText(String.valueOf(user.getAge()));
}
});
}
// 3. 被观察者状态变化(如网络请求成功后)
private void fetchUserSuccess(User user) {
// .postValue():在子线程更新数据;.setValue():在主线程更新数据
mUserLiveData.postValue(user);
}
优点与缺点
-
优点:解耦观察者与被观察者、支持广播通知(一对多)、LiveData 等实现可避免内存泄漏
-
缺点:观察者过多时通知效率低;循环依赖可能导致问题(如 A 观察 B,B 观察 A)
2. 策略模式(Strategy)
定义
定义一系列算法,将它们封装起来并使它们可互换,使得算法可独立于使用它的客户端而变化。
安卓核心场景
-
动画插值器(
TimeInterpolator
,如线性、加速、减速策略) -
RecyclerView
布局管理器(LinearLayoutManager
、GridLayoutManager
、StaggeredGridLayoutManager
) -
网络请求策略(如 WiFi 下用 OkHttp,移动网络下用 Retrofit 缓存策略)
代码示例:动画插值器(策略模式)
Android 的Animation
通过setInterpolator
设置不同的插值策略(算法),实现不同的动画效果:
java
// 1. 策略接口:TimeInterpolator(定义算法接口)
public interface TimeInterpolator {
// 输入:动画进度(0\~1);输出:插值后的进度(控制动画速度)
float getInterpolation(float input);
}
// 2. 具体策略1:LinearInterpolator(线性插值,匀速动画)
public class LinearInterpolator implements TimeInterpolator {
@Override
public float getInterpolation(float input) {
return input; // 输入=输出,匀速
}
}
// 3. 具体策略2:AccelerateDecelerateInterpolator(加速减速插值)
public class AccelerateDecelerateInterpolator implements TimeInterpolator {
@Override
public float getInterpolation(float input) {
// 公式:(cos((input + 1) \* π) / 2) + 0.5 → 先加速后减速
return (float)(Math.cos((input + 1) \* Math.PI) / 2.0f) + 0.5f;
}
}
// 4. 上下文:Animation(使用策略的客户端)
Animation animation = new TranslateAnimation(0, 500, 0, 0);
animation.setDuration(1000); // 动画时长1秒
// 设置不同策略(动态切换算法,无需修改Animation)
// 策略1:匀速动画
animation.setInterpolator(new LinearInterpolator());
// 策略2:先加速后减速动画
// animation.setInterpolator(new AccelerateDecelerateInterpolator());
// 执行动画
view.startAnimation(animation);
优点与缺点
-
优点 :算法可互换、扩展灵活(新增策略无需修改客户端)、避免大量
if-else
(如不用策略模式需判断用哪种插值器) -
缺点:策略类数量增加(每个算法对应一个类);客户端需了解所有策略(才能选择合适的策略)
3. 命令模式(Command)
定义
将请求封装成对象,使得可以用不同的请求对客户进行参数化,支持请求的排队、记录、撤销和重做。
安卓核心场景
-
Handler
的Message
(将 "任务" 封装成Message
,放入消息队列,Looper
执行) -
撤销 / 重做操作(如文本编辑、绘图应用)
-
事件分发(如
View
的TouchEvent
封装成命令,传递给不同的View
处理)
代码示例:Handler 的 Message(命令模式)
Message
封装了 "任务"(如更新 UI、延迟执行逻辑),Handler
负责发送命令,Looper
负责执行命令:
java
// 1. 命令对象:Message(封装任务信息)
Message message = Message.obtain();
message.what = 1; // 命令标识(区分不同任务)
message.obj = "更新UI的参数"; // 命令参数
// 2. 命令发送者:Handler(发送命令到消息队列)
private Handler mHandler = new Handler(Looper.getMainLooper()) {
// 3. 命令执行者:handleMessage(执行命令)
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
// 执行命令:更新UI
String param = (String) msg.obj;
tvContent.setText(param);
break;
case 2:
// 执行其他命令
break;
}
}
};
// 发送命令(立即执行)
mHandler.sendMessage(message);
// 发送延迟命令(3秒后执行)
mHandler.sendEmptyMessageDelayed(2, 3000);
优点与缺点
-
优点:解耦发送者与执行者、支持命令排队 / 撤销 / 重做、便于日志记录(如记录所有命令)
-
缺点:命令类数量增加(每个任务对应一个命令);简单场景下略显复杂
4. 迭代器模式(Iterator)
定义
提供一种方法顺序访问一个聚合对象中的各个元素,而无需暴露该对象的内部表示。
安卓核心场景
-
集合遍历(如
ArrayList
、HashMap
的iterator()
方法) -
RecyclerView
的LayoutManager
(迭代子View
进行布局) -
数据库查询结果遍历(如
Cursor
迭代查询结果)
代码示例:ArrayList 迭代器
java
// 1. 聚合对象:ArrayList(实现Iterable接口,提供迭代器)
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
// 2. 迭代器:Iterator(定义遍历接口)
Iterator<String> iterator = list.iterator();
// 3. 遍历元素(无需关心ArrayList内部结构)
while (iterator.hasNext()) {
String item = iterator.next();
Log.d("Iterator", "item: " + item);
// 支持删除元素(安全删除,避免ConcurrentModificationException)
if (item.equals("B")) {
iterator.remove();
}
}
// 增强for循环(本质也是迭代器)
for (String item : list) {
Log.d("ForEach", "item: " + item); // 输出A、C
}
优点与缺点
-
优点:统一遍历接口(不同聚合对象用相同方式遍历)、隐藏内部结构(如 ArrayList 的数组、LinkedList 的链表)
-
缺点:简单聚合对象(如数组)使用迭代器略显冗余;新增聚合类型需实现迭代器
五、安卓设计模式高频面试题
1. 单例模式有哪些实现方式?安卓中使用单例需要注意什么?
解答:
-
实现方式:饿汉式、懒汉式(双重检查锁)、静态内部类、枚举(详见上文)。
-
安卓注意事项:
-
内存泄漏 :单例持有
Activity/Fragment
的Context
会导致内存泄漏,需使用Application Context
(如getApplicationContext()
)。 -
多进程问题 :多进程会创建多个虚拟机,单例实例不共享(如需共享需用
ContentProvider
、SP
或AIDL
)。 -
序列化问题 :普通单例序列化后会生成新实例,需重写
readResolve()
方法返回原实例,或用枚举单例(天然防序列化)。 -
反射破坏:通过反射调用私有构造器可创建新实例,枚举单例可避免此问题(JVM 禁止反射调用枚举构造器)。
2. RecyclerView.Adapter 体现了哪种设计模式?请解释其原理。
解答:
-
设计模式:适配器模式(Adapter Pattern)。
-
原理:
-
目标接口 :
RecyclerView.Adapter
(系统定义的接口,要求实现onCreateViewHolder
、onBindViewHolder
、getItemCount
等方法)。 -
适配者 :业务数据(如
User
列表、商品列表等,格式与RecyclerView
所需的ViewHolder
不兼容)。 -
适配器 :自定义
Adapter
(如UserAdapter
),将业务数据转换为RecyclerView
可识别的ViewHolder
:
-
onCreateViewHolder
:创建ViewHolder
(视图容器),加载 Item 布局。 -
onBindViewHolder
:将业务数据绑定到ViewHolder
的控件上(如设置文本、图片)。 -
getItemCount
:返回数据数量,供RecyclerView
计算布局。
- 作用 :解耦业务数据与
RecyclerView
的展示逻辑,使同一RecyclerView
可展示不同类型的数据(只需更换Adapter
)。
3. 安卓中哪些组件或框架使用了观察者模式?请举例说明。
解答:
安卓中观察者模式应用广泛,典型场景包括:
- LiveData:
-
被观察者:
LiveData
(持有数据,状态变化时通知观察者)。 -
观察者:
Activity/Fragment
(实现Observer
接口,接收数据变化并更新 UI)。 -
优势:自动感知
LifecycleOwner
(如 Activity)的生命周期,避免内存泄漏(Activity 销毁后自动移除观察者)。
- EventBus/RxJava:
-
被观察者:
EventBus
的Event
、RxJava 的Observable
。 -
观察者:
EventBus
的@Subscribe
方法、RxJava 的Observer
。 -
优势:解耦组件通信(如 Activity 与 Fragment、Service 与 Activity),支持线程切换。
- BroadcastReceiver:
-
被观察者:系统 / 应用广播(如
ACTION_PACKAGE_ADDED
、自定义广播)。 -
观察者:
BroadcastReceiver
(通过onReceive
接收广播并处理)。 -
优势:实现跨应用、跨组件的事件通知。
- DataBinding:
-
被观察者:
ObservableField
、BaseObservable
子类(持有数据)。 -
观察者:XML 布局中的控件(如
TextView
的android:text="@{user.name}"
)。 -
优势:数据变化时自动更新 UI,无需手动调用
findViewById
和setText
。
4. 建造者模式和工厂模式的区别是什么?分别适用于什么场景?
解答:
对比维度 | 建造者模式(Builder) | 工厂模式(Factory) |
---|---|---|
核心目标 | 构建复杂对象(多属性、多步骤) | 创建简单 / 中等复杂度对象 |
构建过程 | 分步构建(链式调用设置属性,最后build ) |
一步创建(调用工厂方法直接返回对象) |
参数支持 | 支持大量可选参数(如AlertDialog 的标题、内容、按钮) |
多为必选参数(如 Retrofit 创建 Service) |
灵活性 | 可定制对象的每个属性(如User 的年龄、电话、邮箱) |
固定对象结构(工厂返回的对象属性相对固定) |
适用场景 | 1. 复杂对象创建(如AlertDialog 、OkHttp Request )2. 多可选参数的对象(如用户信息、订单信息)3. 第三方库(Glide、Retrofit Builder) |
1. 简单对象创建(如 Retrofit Service、自定义 View)2. 产品类型固定(如仅创建几种类型的对象)3. 客户端无需关心创建细节(如仅需调用工厂方法) |
示例:
-
建造者模式:用
AlertDialog.Builder
创建带标题、内容、确定 / 取消按钮的对话框(多步骤、多可选参数)。 -
工厂模式:用
Retrofit.create()
创建ApiService
实例(一步创建,参数固定为 Service 接口)。
5. Retrofit 中用到了哪些设计模式?请详细说明。
解答:
Retrofit 是安卓网络请求的核心框架,集成了多种设计模式:
- 工厂模式:
-
场景:
Retrofit.Builder
创建Retrofit
实例、create()
方法创建Service
接口实例。 -
原理:
Retrofit.Builder
通过链式调用设置baseUrl
、ConverterFactory
等参数,最后build()
返回Retrofit
实例;create()
方法通过工厂逻辑生成Service
接口的动态代理对象。
- 代理模式(动态代理):
-
场景:
Retrofit.create(Class<T> service)
生成Service
接口实例。 -
原理:通过
Proxy.newProxyInstance
生成动态代理对象,拦截Service
接口的方法调用,解析方法上的注解(如@GET
、@POST
、@Query
),生成Request
对象,最终通过 OkHttp 发起网络请求。
- 适配器模式:
-
场景:
ConverterFactory
(如GsonConverterFactory
、JacksonConverterFactory
)。 -
原理:
ConverterFactory
将网络响应的ResponseBody
(原始数据)适配为业务所需的 Java 对象(如User
、List<Goods>
),解耦数据解析与网络请求逻辑。
4 策略模式:
-
场景:
CallAdapter.Factory
(如RxJavaCallAdapterFactory
、CoroutineCallAdapterFactory
)。 -
原理:
CallAdapter
定义网络请求结果的转换策略,不同的CallAdapter
将Call
对象转换为不同类型(如Observable
、Flow
、Deferred
),客户端可根据需求选择不同策略。
6. 为什么说 Application 是单例模式的应用?它的生命周期有什么特点?
解答:
- Application 是单例的原因:
-
系统保证唯一实例 :安卓系统在 APP 启动时会创建且仅创建一个
Application
实例,整个 APP 进程中只有一个Application
对象。 -
全局访问入口 :通过
getApplication()
或getApplicationContext()
可在任意Activity
、Service
、BroadcastReceiver
中获取Application
实例,符合单例模式的 "全局唯一访问" 特征。 -
私有构造(隐含) :
Application
的构造器是 public 的,但系统禁止开发者手动new Application
(手动创建的实例无法被系统管理,且与系统创建的实例冲突),本质上仅有系统能创建实例,符合单例模式的 "唯一实例" 特征。
- Application 生命周期特点:
-
生命周期与 APP 进程一致 :
Application
在 APP 进程创建时初始化(onCreate
),在 APP 进程销毁时销毁(无明确的onDestroy
方法,进程销毁时资源自动释放)。 -
初始化时机早 :
Application.onCreate()
在所有Activity
、Service
、Receiver
创建前执行,适合初始化全局资源(如网络请求客户端、数据库、全局配置)。 -
注意事项:
-
避免在
onCreate
中执行耗时操作(如网络请求、大量 IO),会导致 APP 启动慢(ANR 风险)。 -
避免存储大量数据(如大列表),会占用内存,可能导致 OOM。
-
多进程场景下,每个进程会创建独立的
Application
实例(需在onCreate
中判断进程名,避免重复初始化)。
六、总结
设计模式是安卓开发的 "内功",其核心不是死记硬背 23 种模式,而是理解 "如何用标准化方案解决特定问题"。在实际开发中:
-
创建型模式:解决 "对象如何创建" 的问题(如单例确保唯一实例,建造者简化复杂对象创建)。
-
结构型模式:解决 "类 / 对象如何组合" 的问题(如适配器解耦接口,装饰者扩展功能)。
-
行为型模式:解决 "对象如何通信" 的问题(如观察者实现通知,策略模式切换算法)。