当前位置: 首页 > ops >正文

掌握设计模式--模板方法模式

模板方法模式(Template Method Pattern)

模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个操作中的算法骨架,并允许子类在不改变算法结构的情况下重新定义算法的某些步骤。

核心思想:模板方法定义算法骨架,浅白地说,定义通用的逻辑框架、控制流程和调用顺序,而具体的实现将延迟到子类,从而在不改变结构的前提下扩展算法的灵活性。再简单点说:定义了一个处理逻辑的步骤(一个骨架),具体的处理逻辑由子类继承后实现(真正的血肉)。

主要组成部分

  1. 抽象类(AbstractClass)

  • 定义模板方法,模板方法包含算法的骨架。

  • 实现一些不变的步骤,或声明需要子类实现的抽象方法。

  1. 具体类(ConcreteClass)

  • 实现抽象类中声明的抽象方法,从而完成算法的具体步骤。

案例实现

实现一个简单的自定义锁,展示如何利用模板方法模式来定义锁的行为。

案例类图

image

定义抽象类 AbstractLock

AbstractLock 提供了模板方法(lock 和 unlock),而具体的处理逻辑是获取锁和释放锁方法tryAcquire 和 tryRelease,这两个方法的具体实现交由子类完成。

// 抽象类定义锁的框架
public abstract class AbstractLock {// 模板方法:锁的流程固定public final void lock() {if (!tryAcquire()) { // 尝试获取锁waitForLock();   // 获取失败时等待}}// 模板方法:解锁的流程固定public final void unlock() {if (tryRelease()) { // 尝试释放锁notifyWaitingThreads(); // 唤醒等待的线程}}// 钩子方法:尝试获取锁(子类实现)protected abstract boolean tryAcquire();// 钩子方法:尝试释放锁(子类实现)protected abstract boolean tryRelease();// 默认行为:等待获取锁(可以覆盖)protected void waitForLock() {try {synchronized (this) {wait(); // 阻塞线程}} catch (InterruptedException e) {Thread.currentThread().interrupt();}}// 默认行为:通知等待线程(可以覆盖)protected void notifyWaitingThreads() {synchronized (this) {notifyAll(); // 唤醒所有等待线程}}
}

实现具体的锁 SimpleLock

SimpleLock 继承了 AbstractLock,并实现了具体的锁逻辑:

public class SimpleLock extends AbstractLock {private boolean isLocked = false; // 锁状态private Thread lockingThread = null; // 持有锁的线程@Overrideprotected synchronized boolean tryAcquire() {if (!isLocked) {isLocked = true;lockingThread = Thread.currentThread();return true;}return false;}@Overrideprotected synchronized boolean tryRelease() {if (Thread.currentThread() == lockingThread) {isLocked = false;lockingThread = null;return true;}return false;}
}

测试 SimpleLock

通过多线程模拟锁的使用场景

public class TemplateLockExample {public static void main(String[] args) {SimpleLock lock = new SimpleLock();Runnable task = () -> {lock.lock(); // 获取锁try {System.out.println(Thread.currentThread().getName() + " acquired the lock");Thread.sleep(1000); // 模拟任务执行} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println(Thread.currentThread().getName() + " released the lock");lock.unlock(); // 释放锁}};// 启动多个线程测试锁的互斥Thread t1 = new Thread(task, "Thread-1");Thread t2 = new Thread(task, "Thread-2");Thread t3 = new Thread(task, "Thread-3");t1.start();t2.start();t3.start();}
}

运行结果

Thread-1 获得锁
Thread-1 释放锁
Thread-3 获得锁
Thread-2 获得锁
Thread-2 释放锁
Thread-3 释放锁

注:该案例并未正确实现完整的锁机制,仅仅为了讲述模版方法模式。

分析

  1. 模板方法的作用lock 和 unlock 方法在 AbstractLock 中定义了锁的固定流程,子类只需实现具体的 tryAcquire 和 tryRelease 方法即可。

  2. 扩展性:可以通过继承 AbstractLock 实现不同的锁机制,例如:读写锁、可重入锁、公平锁等。

  3. 简化逻辑:模板方法模式将通用逻辑集中在抽象类中,避免子类重复实现。

优缺点和应用场景

优点

  1. 提高代码复用性,通用代码在父类中实现。

  2. 提供扩展灵活性,通过子类覆盖实现具体步骤。

  3. 符合开闭原则,增加新功能时无需修改模板方法。

缺点

  1. 每个具体实现都需要定义子类,导致类数量增加。

  2. 对算法步骤的控制较为严格,可能不适合所有场景。

应用场景

  1. 多个类的逻辑相同但细节不同:公共部分代码抽取到父类,具体实现由子类提供。

  2. 避免代码重复:在模板方法中实现通用逻辑,特定逻辑由子类实现。

  3. 固定框架:需要确保子类遵循算法的基本结构。

模板方法模式的应用

  1. Java中锁的实现(模版类AbstractQueuedSynchronizer,简称AQS),子类(如ReentrantLockReentrantReadWriteLock等)通过继承AQS并实现其抽象方法(如tryAcquiretryRelease等)来完成具体的同步逻辑;

  2. Java Swing 中的框架设计(例如 paint() 方法是一个模板方法);

  3. JUnit 中的测试框架(测试用例继承 TestCase 并重写具体方法)。

总结

在一个抽象类中定义一个模板方法作为算法骨架,其中包含若干通用逻辑和抽象步骤,通过子类实现这些抽象步骤的具体逻辑,确保算法流程固定且具有灵活扩展性,同时实现代码复用和行为定制

文章转载自:渊渟岳

原文链接:掌握设计模式--模板方法模式 - 渊渟岳 - 博客园

体验地址:JNPF快速开发平台

http://www.xdnf.cn/news/19544.html

相关文章:

  • Java基础(十):关键字static详解
  • 慢病管理重构药店价值:数字化平台与物联网技术如何驱动行业升级?
  • Python分布式消息队列高并发处理与可靠性保障实战
  • 校企合作| 长春大学旅游学院副董事长张海涛率队到访卓翼智能,共绘无人机技术赋能“AI+文旅”发展新蓝图
  • 亚马逊美加站点物流新规解读:库存处理逻辑重构与卖家应对策略
  • 在时间序列中增加一个阶跃对长期趋势变化的影响
  • 发现宝藏!免费任务书生成器大推荐
  • 从 WPF 到 Avalonia 的迁移系列实战篇6:ControlTheme 和 Style区别
  • .NetCore下Ocelot + Nacos 实现负载均衡
  • qt QWebSocket详解
  • 数据结构与算法个人学习代码笔记包含leetcode,海贼oj,蓝桥杯,ACM
  • 对于牛客网—语言学习篇—编程初学者入门训练—复合类型:BC140 杨辉三角、BC133 回型矩阵、BC134 蛇形矩阵题目的解析
  • Ansible 变量与加密文件全解析:从基础定义到安全实践
  • 了解名词ARM Linux的SOC
  • TIOBE 8月编程语言榜深度解析:Python占比突破26%,Perl成最大黑马
  • Kaia AMA 全回顾:如何让 Web3 无痕融入2.5 亿用户日常?9 月 7 日中国行揭秘!
  • 一键提取,是真强呀!~
  • buuctf_php(极客大挑战 2019)
  • 从程序员到「认识罕见病 DAO」发起人,他用 Web3 承载爱与责任
  • Linux 文本处理四剑客:cut, sort, uniq, tr
  • lua脚本在redis中如何单步调试?
  • 一文吃透 deviceQuery:从安装到输出解读,彻底验证服务器 GPU 环境
  • AlDente Pro for Mac电脑 充电限制保护工具
  • Go 面试题:Goroutine 和 GMP 模型解析
  • 最快的 C 语言 JSON 库 - yyjson
  • 阿里云日志服务之WebTracking 小程序端 JavaScript SDK (阿里SDK埋点和原生uni.request请求冲突问题)
  • 2025全球绿色发展与健康生活方式高峰论坛 推动HLCC国际认证体系全球化实施
  • VGG改进(7):基于Spatial Attention的性能优化
  • 跨平台游戏引擎 Axmol-2.8.0 发布
  • Prettier代码格式化工具测评:支持JS/TS/Vue多语言,兼容ESLint实现团队代码格式统一