在Android开发中,模板方法模式(Template Method Pattern)用于定义算法的骨架,将具体步骤延迟到子类实现。核心是抽象类声明固定流程的"模板方法"(如final
修饰) 优势:提升代码复用性、规范执行流程、便于扩展。
1.概念
2个点,就是继承,一个公共的实现方法
模板方法模式(Template Method) 是一种行为型设计模式 ,它在抽象类中定义算法的骨架,将某些步骤延迟到子类实现。核心思想:
- 抽象类 提供 模板方法 (
final
修饰,定义算法流程)。 - 具体子类 重写特定步骤(如
initData()
、renderUI()
),但不改变算法结构。
✅ 核心原则 : "不要调用我,我会调用你。" (Hollywood Principle)
2.在Android源码中的应用场景
典型示例:Activity
的生命周期
typescript
public class Activity {
// 模板方法:定义生命周期流程(不可重写)
public final void performCreate(Bundle savedInstanceState) {
onCreate(savedInstanceState);
onStart();
// ...
}
// 基本方法:子类可重写具体步骤
protected void onCreate(@Nullable Bundle savedInstanceState) {}
protected void onStart() {}
}
-
系统控制流程 :Android 框架调用
performCreate()
,开发者只需实现onCreate()
等钩子方法。 -
其他应用:
AsyncTask
:doInBackground()
,onPostExecute()
View
的绘制:onMeasure()
,onLayout()
,onDraw()
3.UML图

4.语音项目的例子和没用设计模式的对比
4.1 没有使用模板方法
typescript
// 基础WAV录音器
public class SimpleWavRecorder {
private static final String TAG = "SimpleWavRecorder";
public void startRecordingSession() {
// 1. 准备录音
Log.i(TAG, "初始化录音环境...");
verifyMicrophoneAccess();
setupTempStorage();
// 2. 开始录音
Log.d(TAG, "开始录制无损WAV音频...");
// WAV录音具体实现...
captureAudioStream();
// 3. 停止录音
Log.d(TAG, "停止WAV录音");
haltRecording();
// 4. 保存录音
Log.i(TAG, "音频已保存为WAV格式");
persistRecording();
// 5. 释放资源
Log.i(TAG, "释放资源");
cleanupResources();
}
private void verifyMicrophoneAccess() {
Log.i(TAG, "检查麦克风权限...");
// 实际权限检查逻辑
}
private void setupTempStorage() {
Log.i(TAG, "创建临时音频文件");
// 文件创建逻辑
}
private void captureAudioStream() {
// WAV音频采集实现
}
private void haltRecording() {
// 停止录音逻辑
}
private void persistRecording() {
// 保存WAV文件逻辑
}
private void cleanupResources() {
// 资源释放逻辑
}
}
scala
// 2. 具体实现类:标准WAV录音器
public class WavAudioRecorder extends AudioRecorderTemplate {
@Override
protected void startRecording() {
// 实现WAV录音逻辑
Log.d("WavRecorder", "开始录制无损WAV音频...");
}
@Override
protected void stopRecording() {
Log.d("WavRecorder", "停止WAV录音");
}
}
scss
// 使用示例 - 录音控制器
public class AudioCaptureController {
private SimpleWavRecorder wavRecorder;
private CompactMp3Recorder mp3Recorder;
public void init() {
wavRecorder = new SimpleWavRecorder();
mp3Recorder = new CompactMp3Recorder();
}
public void startWavRecording() {
new Thread(() -> {
wavRecorder.startRecordingSession();
}).start();
}
public void startMp3Recording() {
new Thread(() -> {
mp3Recorder.executeRecording();
}).start();
}
// Activity中使用
public void setupInActivity(RecordingActivity activity) {
activity.findViewById(R.id.tv_page_name).setOnClickListener(v -> {
startWavRecording();
});
activity.findViewById(R.id.tv_page_name).setOnClickListener(v -> {
startMp3Recording();
});
}
}

没有使用模版方法的缺点:
代码重复,导致相同修改需在多处重复操作
流程一致性无法保证:不同实现类可能采用不同的流程顺序
扩展需完全重写
4.2 使用模板方法
csharp
// 1. 抽象基类:定义录音流程模板
public abstract class AudioRecorderTemplate {
// 模板方法:定义录音流程(final 防止子类覆盖)
public final void recordAudio() {
prepareRecording(); // 1. 准备录音
startRecording(); // 2. 开始录音(子类实现)
processAudio(); // 3. 处理音频(可选钩子)
stopRecording(); // 4. 停止录音(子类实现)
saveRecording(); // 5. 保存录音(默认实现)
releaseResources(); // 6. 释放资源(可选钩子)
}
// 具体步骤实现 ===================================
private void prepareRecording() {
// 公共准备逻辑
Log.i("AudioRecorder", "初始化录音环境...");
checkMicrophonePermission();
createTempFile();
}
// 抽象方法:必须由子类实现 ========================
protected abstract void startRecording(); // 开始录音
protected abstract void stopRecording(); // 停止录音
// 钩子方法:子类可选择覆盖 ========================
protected void processAudio() {
// 默认空实现(子类可扩展)
}
protected void releaseResources() {
// 默认资源释放
Log.i("AudioRecorder", "释放默认资源");
}
// 公共方法 ======================================
private void checkMicrophonePermission() {
Log.i("AudioRecorder", "检查麦克风权限...");
}
private void createTempFile() {
Log.i("AudioRecorder", "创建临时音频文件");
}
protected void saveRecording() {
// 默认保存逻辑
Log.i("AudioRecorder", "音频已保存为WAV格式");
}
}
typescript
// 压缩MP3录音器
public class CompactMp3Recorder {
private static final String TAG = "CompactMp3Recorder";
public void executeRecording() {
// 1. 准备录音
Log.i(TAG, "初始化录音环境...");
verifyMicrophoneAccess();
setupTempStorage();
// 2. 开始录音
Log.d(TAG, "开始录制MP3音频...");
// MP3录音具体实现...
initAudioCapture();
// 3. 实时压缩音频数据
Log.d(TAG, "实时压缩音频数据...");
compressAudio();
// 4. 停止录音
Log.d(TAG, "停止MP3录音");
terminateRecording();
// 5. 保存录音
Log.i(TAG, "音频已保存为MP3格式");
storeCompressedAudio();
// 6. 释放资源
Log.i(TAG, "释放资源");
releaseEncodingTools();
}
private void verifyMicrophoneAccess() {
Log.i(TAG, "检查麦克风权限...");
// 实际权限检查逻辑
}
private void setupTempStorage() {
Log.i(TAG, "创建临时音频文件");
// 文件创建逻辑
}
private void initAudioCapture() {
// MP3音频采集实现
}
private void compressAudio() {
// 音频压缩逻辑
}
private void terminateRecording() {
// 停止录音逻辑
}
private void storeCompressedAudio() {
// 保存MP3文件逻辑
}
private void releaseEncodingTools() {
Log.d(TAG, "释放MP3编码器");
// 编码器释放逻辑
}
}
typescript
// 3. 具体实现类:压缩MP3录音器(带额外处理)
public class CompressedAudioRecorder extends AudioRecorderTemplate {
@Override
protected void startRecording() {
// 实现MP3录音逻辑
Log.d("Mp3Recorder", "开始录制MP3音频...");
}
@Override
protected void stopRecording() {
Log.d("Mp3Recorder", "停止MP3录音");
}
// 覆盖钩子方法:添加音频压缩处理
@Override
protected void processAudio() {
super.processAudio();
Log.d("Mp3Recorder", "实时压缩音频数据...");
}
// 覆盖保存方法
@Override
protected void saveRecording() {
Log.i("Mp3Recorder", "音频已保存为MP3格式");
}
// 添加额外资源释放
@Override
protected void releaseResources() {
super.releaseResources();
Log.d("Mp3Recorder", "释放MP3编码器资源");
}
}
使用
scala
// 4. 使用示例(在Activity中)
public class RecordingActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
TextView btnRecordWav = findViewById(R.id.tv_page_name);
TextView btnRecordMp3 = findViewById(R.id.btn_go_cart);
btnRecordWav.setOnClickListener(v -> {
AudioRecorderTemplate recorder = new WavAudioRecorder();
recorder.recordAudio(); // 执行模板方法
});
btnRecordMp3.setOnClickListener(v -> {
AudioRecorderTemplate recorder = new CompressedAudioRecorder();
recorder.recordAudio(); // 执行模板方法
});
}
}

设计优势解析
-
流程标准化
所有录音类型共享相同的
recordAudio()
流程,避免代码重复 -
灵活扩展
- 添加新录音格式只需继承基类(如
AacAudioRecorder
) - 通过钩子方法(
processAudio()
,releaseResources()
)实现差异化
- 添加新录音格式只需继承基类(如
-
保护核心流程
final
模板方法防止子类破坏录音流程顺序 -
代码复用
权限检查、文件创建等通用逻辑在基类一次性实现
实战案例:语音录制功能
重构前后对比
特性 | 未使用模板方法 (优化类名版) | 使用模板方法 |
---|---|---|
类结构 | 完全独立的类 (SimpleWavRecorder , CompactMp3Recorder ) |
继承层次结构 (BaseAudioRecorder ← StandardWavRecorder 等) |
代码复用 | 公共逻辑在每个类中重复实现 | 公共逻辑在基类中统一实现 |
扩展性 | 添加新格式需完整实现所有方法 | 只需实现抽象方法和覆盖钩子 |
维护性 | 修改公共逻辑需更新所有类 | 只需修改基类 |
流程一致性 | 各实现类流程可能不同 | 统一流程由模板方法保证 |
错误预防 | 无强制流程机制 | final 模板方法防止流程篡改 |
代码量 | 冗余代码多(约+40%) | 精简高效 |
可读性 | 每个类都是完整实现,但重复代码多 | 关注点分离,结构清晰 |
问题:用了模板方法,如果要新增一个mp4的录音器,但是里面多一个步骤,mp4的视频解码videoCode 问题:如果有一个mpg格式的,顺序不一样,怎么办 使用模板方法+策略模式组合
5.优点
- 代码复用:公共流程在抽象类中实现。
- 扩展性强:新增功能只需扩展子类。
- 封装不变部分:算法骨架稳定,保护核心流程。
- 符合开闭原则:对扩展开放(子类),对修改关闭(模板方法)。
6.和相似的设计模式的区别
比较独特,没有特别容易和其他设计模式混淆的!
总结
在 Android 开发中,模板方法模式适用于:
-
功能有固定流程(如生命周期、异步任务)。
-
需要避免重复代码且允许部分步骤定制化。
经典场景 :BaseActivity
封装通用逻辑(数据加载/权限检查),子类专注差异实现。
项目的地址: github.com/pengcaihua1...