9.Android 设计模式 模板方法 在项目中的实战

在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() 等钩子方法。

  • 其他应用

    • AsyncTaskdoInBackground(), 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();  // 执行模板方法
        });
    }
}

设计优势解析

  1. 流程标准化

    所有录音类型共享相同的 recordAudio() 流程,避免代码重复

  2. 灵活扩展

    • 添加新录音格式只需继承基类(如 AacAudioRecorder
    • 通过钩子方法(processAudio(), releaseResources())实现差异化
  3. 保护核心流程
    final 模板方法防止子类破坏录音流程顺序

  4. 代码复用

    权限检查、文件创建等通用逻辑在基类一次性实现

实战案例:语音录制功能

重构前后对比

特性 未使用模板方法 (优化类名版) 使用模板方法
类结构 完全独立的类 (SimpleWavRecorder, CompactMp3Recorder) 继承层次结构 (BaseAudioRecorderStandardWavRecorder等)
代码复用 公共逻辑在每个类中重复实现 公共逻辑在基类中统一实现
扩展性 添加新格式需完整实现所有方法 只需实现抽象方法和覆盖钩子
维护性 修改公共逻辑需更新所有类 只需修改基类
流程一致性 各实现类流程可能不同 统一流程由模板方法保证
错误预防 无强制流程机制 final模板方法防止流程篡改
代码量 冗余代码多(约+40%) 精简高效
可读性 每个类都是完整实现,但重复代码多 关注点分离,结构清晰

问题:用了模板方法,如果要新增一个mp4的录音器,但是里面多一个步骤,mp4的视频解码videoCode 问题:如果有一个mpg格式的,顺序不一样,怎么办 使用模板方法+策略模式组合

5.优点

  • 代码复用:公共流程在抽象类中实现。
  • 扩展性强:新增功能只需扩展子类。
  • 封装不变部分:算法骨架稳定,保护核心流程。
  • 符合开闭原则:对扩展开放(子类),对修改关闭(模板方法)。

6.和相似的设计模式的区别

比较独特,没有特别容易和其他设计模式混淆的!

总结

在 Android 开发中,模板方法模式适用于

  • 功能有固定流程(如生命周期、异步任务)。

  • 需要避免重复代码且允许部分步骤定制化。
    经典场景BaseActivity 封装通用逻辑(数据加载/权限检查),子类专注差异实现。

项目的地址: github.com/pengcaihua1...

相关推荐
kangkang-21 分钟前
PC端基于SpringBoot架构控制无人机(三):系统架构设计
java·架构·无人机
ai小鬼头2 小时前
Ollama+OpenWeb最新版0.42+0.3.35一键安装教程,轻松搞定AI模型部署
后端·架构·github
群联云防护小杜5 小时前
构建分布式高防架构实现业务零中断
前端·网络·分布式·tcp/ip·安全·游戏·架构
森焱森6 小时前
垂起固定翼无人机介绍
c语言·单片机·算法·架构·无人机
wenzhangli77 小时前
从源码到思想:OneCode框架模块化设计如何解决前端大型应用痛点
架构·前端框架
秋千码途8 小时前
小架构step系列07:查找日志配置文件
spring boot·后端·架构
Ashlee_code10 小时前
什么是Web3?金融解决方案
开发语言·金融·架构·eclipse·web3·区块链·php
WebInfra12 小时前
如何在程序中嵌入有大量字符串的 HashMap
算法·设计模式·架构
森焱森13 小时前
APM与ChibiOS系统
c语言·单片机·算法·架构·无人机
安思派Anspire14 小时前
LangGraph + MCP + Ollama:构建强大代理 AI 的关键(一)
前端·深度学习·架构