设计模式 - 模板方法模式 笔记

我们实现一个功能的时候,很多时候,会先写好大致的框架的代码,然后再引入插件、类库来具体实现代码功能。

假设我正在设计一个媒体播放器模块。我先写好一个【是否正在播放】属性,一个【播放】方法,一个【停止播放】方法,【播放】方法中首先判定是否正在播放,没有播放再播放;【停止播放】方法逻辑趋同。

( C# 开发 )

一开始想用一个接口实现,先写好接口作为框架,但是接口中的方法貌似不建议填充内容,问问了问AI,它告诉我:

业界普遍的做法有以下几种:

方案一:抽象基类(最常用、最清晰)

这是最直接的"空框架"实现。先把通用逻辑写好,具体播放/停止逻辑留空让子类实现。

csharp

复制代码
public abstract class PlayerBase
{
    // 框架层:状态字段
    private bool _isPlaying;
    
    // 框架层:只读属性,子类可以获取状态,但最好由基类维护
    public bool IsPlaying => _isPlaying;
    
    // 播放方法:框架实现状态判断 + 状态变更
    public void Play()
    {
        if (IsPlaying)
        {
            Console.WriteLine("已在播放,忽略 Play 调用");
            return;
        }
        
        // 调用子类实现的具体播放逻辑
        OnPlay();
        
        // 播放后修改状态
        _isPlaying = true;
    }
    
    // 停止方法:类似逻辑
    public void Stop()
    {
        if (!IsPlaying)
        {
            Console.WriteLine("已停止,忽略 Stop 调用");
            return;
        }
        
        OnStop();
        _isPlaying = false;
    }
    
    // 子类需要实现的具体行为
    protected abstract void OnPlay();
    protected abstract void OnStop();
}

子类实现:

csharp

复制代码
public class Mp3Player : PlayerBase
{
    protected override void OnPlay()
    {
        Console.WriteLine("MP3 开始播放...");
        // 真正的 MP3 播放逻辑
    }
    
    protected override void OnStop()
    {
        Console.WriteLine("MP3 停止播放");
        // 真正的停止逻辑
    }
}

优点:

  • 完美封装"先判断状态再执行"的通用流程

  • 基类自行维护 IsPlaying 状态,子类无需操心

  • 子类只关心具体播放/停止的实现

  • 符合模板方法模式

方案二:接口 + 抽象基类(更灵活,适合多人协作)

如果你的框架需要定义多个不相关的播放器族,接口用于对外暴露契约,抽象基类用于代码复用。

csharp

复制代码
// 1. 定义公共接口(契约)
public interface IMediaPlayer
{
    bool IsPlaying { get; }
    void Play();
    void Stop();
}

// 2. 提供默认实现框架(可复用)
public abstract class PlayerBase : IMediaPlayer
{
    private bool _isPlaying;
    public bool IsPlaying => _isPlaying;
    
    public void Play()
    {
        if (_isPlaying) return;
        OnPlay();
        _isPlaying = true;
    }
    
    public void Stop()
    {
        if (!_isPlaying) return;
        OnStop();
        _isPlaying = false;
    }
    
    protected abstract void OnPlay();
    protected abstract void OnStop();
}

优点:

  • 接口定义了标准,其它团队可以自己实现接口(不用基类)

  • 基类提供了便捷的实现方式(推荐使用基类)

  • 扩展性更好


而当我问它,这种先搭框架代码,再考虑具体实现的做法,业界最多的称呼是什么:它说就是

模板方法模式, 是吗?就当是吧,在此记录一下(完)

相关推荐
星恒随风3 分钟前
C++ 哈希详解(二):开放定址、哈希桶与 C++ 哈希表底层实现
c++·笔记·学习·哈希算法·散列表
2501_926978331 小时前
AGI封锁的物理边界:发现模式决定封锁可行性
人工智能·经验分享·笔记·ai写作·agi
烬羽1 小时前
NestJS 依赖注入:Controller 里那个没有 new 的 service,到底从哪来的?
设计模式·typescript·nestjs
Mr_liu_6661 小时前
Claude非专业入门实战笔记(附录):关闭Telemetry-遥测,消除无用网络请求与日志噪音
linux·笔记·ubuntu·ai编程
水水不水啊2 小时前
DeepSeek自带的一些插件的功能介绍
笔记·ai·deepseek·harness·dsh
爱编程的Zion2 小时前
Jenkins 从 0 到 1 学习笔记
笔记·学习·jenkins
不会代码的小猴3 小时前
2. 了解Qt
开发语言·c++·笔记·qt·算法
用户9385156350713 小时前
工厂模式与 Nest.js 核心思想 —— 从蜜雪冰城到企业级架构
后端·设计模式·nestjs
2501_9269783313 小时前
AGI 的四种瓶颈:资源型还是发现型--以及DSH的位置
人工智能·经验分享·笔记·ai写作
liuqs33214 小时前
nat123安卓和nat123全端口选型指南,映射工具怎么挑
网络·笔记