| 序号 | 问题 | 原因 |
|---|---|---|
| Q1 | 单例模式(静态内部类、DCL volatile) | 最基础,几乎 100% 必问 |
| Q2 | 观察者模式 + LiveData(生命周期感知) | Android 特有,面试高频 |
| Q3 | 适配器模式(RecyclerView.Adapter) | 日常开发用到,必考 |
| Q4 | 建造者模式(AlertDialog.Builder) | 链式调用典型,常问 |
| Q5 | 责任链模式(View 事件分发) | Android 核心机制,高频 |
| Q6 | 策略模式(动画插值器、算法切换) | 常与 if-else 优化结合问 |
| Q7 | 工厂模式(简单工厂 vs 工厂方法 vs 抽象工厂) | 基础创建型,区分度题 |
| Q8 | 动态代理模式(Retrofit 原理、AOP) | 进阶考点,中高频 |
| Q9 | 模板方法模式(AsyncTask、Activity 生命周期) | 经典框架模式 |
| Q10 | 装饰器模式(ContextWrapper、IO) | 与继承对比,中频 |
| Q11 | 外观模式(SDK 封装、Context) | 低频但设计思想好 |
| Q12 | 对比:策略模式 vs 状态模式 | 结构相似,易混淆 |
| Q13 | 对比:适配器模式 vs 装饰器模式 | 包装类区别,常考 |
| Q14 | 对比:代理模式 vs 装饰器模式 | 代码相似,意图不同 |
| Q15 | 对比:工厂方法模式 vs 抽象工厂模式 | 产品族 vs 产品等级 |
| Q16 | 对比:简单工厂 vs 工厂方法 | 扩展性对比 |
Q1:单例模式
面试官问 :请你说说单例模式有哪几种写法?在 Android 中你一般用哪种?DCL 为什么要加 volatile?
答案要点
- 五种实现:饿汉、懒汉、DCL、静态内部类、枚举。
- Android 最佳:静态内部类(懒加载、无线程锁);枚举可防反射破坏。
- DCL 必须加
volatile:防止instance = new Singleton()指令重排导致其他线程拿到半初始化对象。
流程图
源码(语音引擎管理器)
java
public class VoiceEngineManager {
private VoiceEngineManager() {}
private static class Holder {
private static final VoiceEngineManager INSTANCE = new VoiceEngineManager();
}
public static VoiceEngineManager getInstance() { return Holder.INSTANCE; }
private SpeechRecognizer recognizer;
public void init(Context ctx) { recognizer = SpeechRecognizer.createRecognizer(ctx); }
}
Q2:观察者模式 + LiveData
面试官问:LiveData 和普通观察者模式有什么区别?为什么能避免内存泄漏?
答案要点
- LiveData 是生命周期感知的观察者,仅在
LifecycleOwner处于 STARTED/RESUMED 时回调。 - 组件销毁时自动移除观察者,无需手动注销,避免内存泄漏。
- 普通观察者需手动管理注册/注销。
流程图
源码(语音识别结果监听)
java
public class VoiceRecognitionLiveData extends LiveData<String> {
private RecognitionListener listener = new RecognitionListener() {
@Override public void onResults(Bundle results) {
setValue(results.getString("text"));
}
};
}
// Activity 中使用
voiceLiveData.observe(this, text -> tvResult.setText(text));
Q3:适配器模式
面试官问:RecyclerView 的 Adapter 是什么模式?如何支持多类型布局?
答案要点
- 对象适配器模式:将数据源适配成 View 视图。
- 多类型:重写
getItemViewType()返回不同布局类型,onCreateViewHolder根据类型创建对应 ViewHolder。
流程图
源码(音频波形适配器)
java
public class AudioWaveformAdapter extends RecyclerView.Adapter<AudioWaveformAdapter.WaveHolder> {
private short[] audioSamples;
@Override public WaveHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_waveform, parent, false);
return new WaveHolder(v);
}
@Override public void onBindViewHolder(WaveHolder holder, int pos) {
holder.waveView.setHeight(scaleAmplitude(audioSamples[pos]));
}
static class WaveHolder extends RecyclerView.ViewHolder { WaveformView waveView; }
}
Q4:建造者模式
面试官问 :AlertDialog.Builder 是哪种设计模式?解决了什么问题?
答案要点
- 建造者模式:构建与表示分离,链式调用避免重叠构造器。
- 解决参数过多、顺序易错、可读性差。
- Android 源码:
AlertDialog.Builder、OkHttpClient.Builder。
流程图
源码(语音合成参数配置)
java
public class TTSConfig {
private float pitch, speed;
private TTSConfig(Builder b) { this.pitch = b.pitch; this.speed = b.speed; }
public static class Builder {
private float pitch = 1.0f, speed = 1.0f;
public Builder setPitch(float pitch) { this.pitch = pitch; return this; }
public Builder setSpeed(float speed) { this.speed = speed; return this; }
public TTSConfig build() { return new TTSConfig(this); }
}
}
Q5:责任链模式
面试官问:Android 事件分发如何体现责任链模式?如何拦截事件?
答案要点
- 事件从 Activity → ViewGroup → View 逐层传递,每个节点可处理/拦截/传递。
- 拦截:重写
onInterceptTouchEvent返回true,事件交由当前 ViewGroup 处理。 - 不消费时向上回传。
流程图
源码(音频事件处理链)
java
public abstract class AudioEventHandler {
protected AudioEventHandler next;
public void setNext(AudioEventHandler h) { this.next = h; }
public abstract void handle(String event);
}
public class WakeupHandler extends AudioEventHandler {
public void handle(String event) {
if ("wakeup".equals(event)) startRecording();
else if (next != null) next.handle(event);
}
}
Q6:策略模式
面试官问:动画插值器是什么模式?它相比 if-else 有什么优势?
答案要点
- 策略模式:定义一族算法,封装可互换,运行时切换。
- 动画插值器:
TimeInterpolator接口 + 线性/加速/回弹等实现。 - 优势:消灭 if-else,符合开闭原则。
流程图
源码(语音降噪算法)
java
public interface NoiseSuppression { short[] denoise(short[] audio); }
public class SpectralSubtraction implements NoiseSuppression { ... }
public class WienerFilter implements NoiseSuppression { ... }
public class AudioProcessor {
private NoiseSuppression strategy;
public void setStrategy(NoiseSuppression s) { this.strategy = s; }
public short[] process(short[] audio) { return strategy.denoise(audio); }
}
Q7:工厂模式(简单工厂 / 工厂方法 / 抽象工厂)
面试官问:简单工厂、工厂方法、抽象工厂有什么区别?Android 中哪里用到?
答案要点
- 简单工厂 :一个工厂根据参数创建多种产品(
BitmapFactory)。 - 工厂方法:每个产品对应一个工厂子类,符合开闭原则。
- 抽象工厂:创建产品族,适合多套方案切换。
- 业务开发用简单工厂,框架扩展用工厂方法。
流程图(简单工厂)
源码(编解码器工厂)
java
public interface AudioCodec { byte[] encode(short[] pcm); }
public class OpusCodec implements AudioCodec { ... }
public class AacCodec implements AudioCodec { ... }
public class CodecFactory {
public static AudioCodec createCodec(String type) {
if ("opus".equals(type)) return new OpusCodec();
else if ("aac".equals(type)) return new AacCodec();
return null;
}
}
Q8:动态代理模式
面试官问:Retrofit 是如何用动态代理实现接口调用的?还有哪些应用场景?
答案要点
- 动态代理运行时生成代理类,对接口方法做无侵入增强(AOP)。
- Retrofit:调用接口方法时被
InvocationHandler拦截,解析注解拼装 HTTP 请求。 - 其他:权限检查、日志耗时、缓存代理。
流程图
源码(录音权限代理)
java
public interface IAudioRecorder { void start(); }
public class RealRecorder implements IAudioRecorder { public void start() { /* 录音 */ } }
IAudioRecorder recorder = (IAudioRecorder) Proxy.newProxyInstance(
IAudioRecorder.class.getClassLoader(),
new Class[]{IAudioRecorder.class},
(proxy, method, args) -> {
if (!hasPermission(RECORD_AUDIO)) { requestPermission(); return null; }
return method.invoke(new RealRecorder(), args);
}
);
Q9:模板方法模式
面试官问 :AsyncTask 和 Activity 生命周期体现了什么模式?什么是钩子方法?
答案要点
- 模板方法模式:父类定义算法骨架,具体步骤延迟到子类实现。
AsyncTask:execute调用onPreExecute→doInBackground→onPostExecute。- 钩子方法:父类默认空实现,子类可选覆写(如
onPreExecute)。
流程图
源码(语音活动检测 VAD)
java
public abstract class VoiceActivityDetector {
public final void detect(short[] frame) {
preProcess(frame); // 钩子
boolean isVoice = doVad(frame); // 必须实现
if (isVoice) onVoiceStart(); // 钩子
postProcess(frame); // 钩子
}
protected void preProcess(short[] f) {}
protected abstract boolean doVad(short[] f);
protected void onVoiceStart() {}
protected void postProcess(short[] f) {}
}
Q10:装饰器模式
面试官问 :ContextWrapper 是装饰器模式吗?和继承有什么区别?
答案要点
- 装饰器模式动态添加职责,不改变原类接口。
ContextWrapper持有Context引用,委托并可在前后增加行为。- 优势:灵活组合多个装饰器,避免子类爆炸。
流程图
源码(音频流回声消除装饰器)
java
public interface AudioStream { byte[] read(); }
public class RawAudioStream implements AudioStream { public byte[] read() { /* 原始数据 */ } }
public class EchoCancelerDecorator implements AudioStream {
private AudioStream decorated;
public EchoCancelerDecorator(AudioStream s) { this.decorated = s; }
public byte[] read() {
byte[] raw = decorated.read();
return cancelEcho(raw);
}
}
Q11:外观模式
面试官问:如何用外观模式简化 SDK 使用?Android 中哪里用到了?
答案要点
- 外观模式为复杂子系统提供统一高层接口。
- Android:
Context封装了多个系统服务;Glide.with().load().into()。 - SDK 设计:将初始化、网络、日志等子模块封装在一个
Facade类中。
流程图
源码(语音 SDK 门面)
java
class WakeupModule { void init() { } }
class AsrModule { void init() { } }
class TtsModule { void init() { } }
public class VoiceSDKFacade {
private WakeupModule wakeup = new WakeupModule();
private AsrModule asr = new AsrModule();
private TtsModule tts = new TtsModule();
public void initAll() { wakeup.init(); asr.init(); tts.init(); }
public void startVoice() { wakeup.startListening(); asr.prepare(); }
}
// 调用方:new VoiceSDKFacade().initAll();
Q12:对比题 - 策略模式 vs 状态模式
面试官问:策略模式和状态模式结构相似,本质区别是什么?
答案要点
| 维度 | 策略模式 | 状态模式 |
|---|---|---|
| 意图 | 算法可互换 | 状态自动切换 |
| 谁控制变化 | 客户端主动设置策略 | 状态对象内部决定下一个状态 |
| 典型场景 | 降噪算法、编码格式 | 录音状态机(空闲→录音→暂停) |
流程图对比
策略模式
状态模式
源码对比
策略(降噪算法)
java
processor.setStrategy(new SpectralSubtraction()); // 客户端主动选
状态(录音状态机)
java
ctx.setState(new RecordingState()); // 状态内部自动切换
Q13:对比题 - 适配器模式 vs 装饰器模式
面试官问:适配器和装饰器都包装对象,如何区分?
答案要点
| 维度 | 适配器模式 | 装饰器模式 |
|---|---|---|
| 意图 | 接口转换 | 动态增加职责 |
| 是否改变接口 | 是 | 否 |
| 嵌套层数 | 通常一层 | 可多层叠加 |
流程图
适配器 :Client → Adapter → Adaptee
装饰器 :Client → DecoratorA → DecoratorB → Component
源码
适配器(麦克风适配)
java
public class MicrophoneAdapter implements AudioSource {
private AndroidMicrophone mic = new AndroidMicrophone();
public byte[] readFrame() { return convert(mic.readRaw()); }
}
装饰器(静音检测)
java
public class SilenceDetectorDecorator implements AudioStream {
private AudioStream decorated;
public byte[] read() { byte[] data = decorated.read(); checkSilence(data); return data; }
}
Q14:对比题 - 代理模式 vs 装饰器模式
面试官问:代理模式和装饰器代码结构很像,怎么区分?
答案要点
| 维度 | 代理模式 | 装饰器模式 |
|---|---|---|
| 意图 | 控制访问(权限、懒加载) | 增加职责(日志、缓存) |
| 创建时机 | 通常编译时确定 | 客户端运行时组合 |
| 典型场景 | Binder 远程代理 | 添加分段、加日志 |
流程图
代理 :Client → Proxy → RealSubject
装饰器 :Client → DecoratorA → DecoratorB → Component
源码
代理(权限代理)
java
public class PermissionProxyRecorder implements AudioRecorder {
private RealAudioRecorder real = new RealAudioRecorder();
public void start() { if (hasPermission()) real.start(); }
}
装饰器(分段录音装饰)
java
public class SegmentRecorderDecorator implements AudioRecorder {
private AudioRecorder decorated;
public void start() { decorated.start(); startSegmentWatcher(); }
}
Q15:对比题 - 工厂方法模式 vs 抽象工厂模式
面试官问:工厂方法和抽象工厂的区别?分别在什么场景使用?
答案要点
| 维度 | 工厂方法 | 抽象工厂 |
|---|---|---|
| 产品数量 | 一种产品 | 一系列相关产品(产品族) |
| 扩展方式 | 新增产品 → 新增工厂子类 | 新增产品族 → 新增具体工厂 |
| 场景 | 编解码器工厂 | 高质量/低功耗音频处理方案 |
流程图
工厂方法 :CreatorA → ProductA,CreatorB → ProductB
抽象工厂 :Factory → {Codec, NoiseSuppression, EchoCanceler}
源码
工厂方法
java
public interface CodecFactory { AudioCodec createCodec(); }
public class OpusCodecFactory implements CodecFactory { ... }
抽象工厂
java
public interface AudioProcessingFactory {
AudioCodec createCodec();
NoiseSuppression createNoiseSuppression();
}
public class HighQualityFactory implements AudioProcessingFactory { ... }
public class LowPowerFactory implements AudioProcessingFactory { ... }
Q16:对比题 - 简单工厂 vs 工厂方法
面试官问:简单工厂和工厂方法有什么实质区别?什么时候用简单工厂就够了?
答案要点
| 维度 | 简单工厂 | 工厂方法 |
|---|---|---|
| 开闭原则 | 违反(新增产品需改工厂类) | 符合(新增产品加新工厂) |
| 产品数量 | 少且稳定 | 多且经常扩展 |
| 复杂度 | 一个类 | 多个工厂类 |
| 典型场景 | BitmapFactory |
插件化框架 |
流程图
简单工厂 :Client → SimpleFactory (switch) → ProductA/B
工厂方法 :Client → FactoryA → ProductA,Client → FactoryB → ProductB
源码
简单工厂(唤醒词引擎)
java
public static WakeupEngine create(String type) {
switch(type) {
case "xiaomi": return new XiaoMiWakeup();
default: return new DefaultWakeup();
}
}
工厂方法
java
public interface WakeupEngineFactory { WakeupEngine createEngine(); }
public class XiaoMiFactory implements WakeupEngineFactory { ... }