【模板方法设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

news2024/10/7 15:27:21

简介

模板方法模式(Template Method Pattern)也叫模板模式,是一种行为型模式。它定义了一个抽象公开类,包含基本的算法骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变算法的结构,只是重定义该算法的某些特定步骤。不同的子类以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。以此基于公共的模板,来实现实现不同的功能。

模板模式适用于一些复杂操作进行步骤分割、抽取公共部分由抽象父类实现、将不同的部分在父类中定义抽象实现、而将具体实现过程由子类完成。对于有多个子类具有共有的方法,且逻辑相同,可以考虑作为模板方法。

作用

  1. 相同的部分父类给出统一的模板,子类大量复用,从而节省代码,复用逻辑。
  2. 封装不变部分,扩展可变部分,行为由父类控制,子类灵活实现,便于维护和扩展。

实现步骤

  1. 创建一个抽象的模板类,定义基本流程,同时定义一些基本方法供子类去实现。
  2. 创建多个子类继承抽象模板,覆盖父类的相关动作和方法。

UML

template-pattern.png

Java代码

抽象模板类

// GameTemplate.java 定义抽象模板类,有抽象方法和具体方法
public abstract class GameTemplate {

   // 抽象方法待子类来实现
   abstract void init();

   abstract void start();

   abstract void end();

   // 可复用的算法流程
   public void play() {

      System.out.println(this.getClass().getSimpleName() + "::play()");

      // 初始化游戏
      init();

      // 开始游戏
      start();

      // 结束游戏
      end();
   }

}

具体业务类,继承抽象模板

// Basketball.java  定义子类覆写父类抽象方法
public class Basketball extends GameTemplate {

   @Override
   void init() {
      System.out.println("Basketball::init() [Basketball Game Initialized! Start playing.]");
   }

   @Override
   void start() {
      System.out.println("Basketball::start() [Basketball Game Started. Enjoy the game!]");
   }

   @Override
   void end() {
      System.out.println("Basketball::end() [Basketball Game Finished!]");
   }

}

// Football.java 定义子类覆写父类抽象方法
public class Football extends GameTemplate {

   @Override
   void init() {
      System.out.println("Football::init() [Football Game Initialized! Start playing.]");
   }

   @Override
   void start() {
      System.out.println("Football::start() [Football Game Started. Enjoy the game!]");
   }

   @Override
   void end() {
      System.out.println("Football::end() [Football Game Finished!]");
   }

}

// Tennis.java 定义子类覆写父类抽象方法
public class Tennis extends GameTemplate {

   @Override
   void init() {
      System.out.println("Tennis::init() [Tennis Game Initialized! Start playing.]");
   }

   @Override
   void start() {
      System.out.println("Tennis::start() [Tennis Game Started. Enjoy the game!]");
   }

   @Override
   void end() {
      System.out.println("Tennis::end() [Tennis Game Finished!]");
   }

   // 在调用父类play之前,如果要执行自己的行为,也可以覆盖父类方法
   // 先执行自己的,再调用父类的方法
   @Override
   public void play() {
      System.out.println("Tennis::play() [Tennis Game play!]");
      super.play();
   }
}

测试调用

    /**
     * 模板方法模式就是当子类具备类似行为的时候,让子类共用一套流程
     * 创建一个公共模板,确定公用流程和操作动作,子类覆盖具体的动作
     */
    GameTemplate football = new Football();
    football.play();

    System.out.println("===");
    GameTemplate basketball = new Basketball();
    basketball.play();

    System.out.println("===");
    GameTemplate tennis = new Tennis();
    tennis.play();

C语言代码

头文件

// func.h

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

typedef struct GameTemplate GameTemplate;
typedef struct Football Football;
typedef struct Basketball Basketball;
typedef struct Tennis Tennis;

// 定义抽象模板,包括各种动作和公共流程
typedef struct GameTemplate
{
  char name[50];
  void (*init)(GameTemplate *game);
  void (*start)(GameTemplate *game);
  void (*end)(GameTemplate *game);
  void (*play)(GameTemplate *game);
} GameTemplate;
void template_play(GameTemplate *game);
GameTemplate *game_template_constructor(char *name);

// 定义子类覆写父类抽象方法
typedef struct Football
{
  char name[50];
  void (*init)(Football *game);
  void (*start)(Football *game);
  void (*end)(Football *game);
  void (*play)(Football *game);
} Football;
Football *football_constructor(char *name);

// 定义子类覆写父类抽象方法
typedef struct Basketball
{
  char name[50];
  void (*init)(Basketball *game);
  void (*start)(Basketball *game);
  void (*end)(Basketball *game);
  void (*play)(Basketball *game);
} Basketball;
Basketball *basketball_constructor(char *name);

// 定义子类覆写父类抽象方法
typedef struct Tennis
{
  char name[50];
  void (*init)(Tennis *game);
  void (*start)(Tennis *game);
  void (*end)(Tennis *game);
  void (*play)(Tennis *game);
} Tennis;
Tennis *tennis_constructor(char *name);

抽象模板类

// game_template.c 定义抽象模板类,有抽象方法和具体方法
#include "func.h"

// 定义抽象模板类的公共部分,这里用struct替代

// 抽象方法待子类来实现
void template_init(GameTemplate *game) {}
void template_start(GameTemplate *game)
{
  printf("\r\n GameTemplate::start() [GameTemplate Initialized! Start playing.]");
}
void template_end(GameTemplate *game) {}

// 可复用的算法流程
void template_play(GameTemplate *game)
{
  printf("\r\n GameTemplate::play() [name=%s]", game->name);

  // 初始化游戏
  game->init(game);

  // 开始游戏
  game->start(game);

  // 结束游戏
  game->end(game);
}

GameTemplate *game_template_constructor(char *name)
{
  // printf("\r\n game_template_constructor() [构建GameTemplate]");
  GameTemplate *game = (GameTemplate *)malloc(sizeof(GameTemplate));
  strcpy(game->name, name);
  game->init = &template_init;
  game->start = &template_start;
  game->end = &template_end;
  game->play = &template_play;
  return game;
}

具体业务类,继承抽象模板

// basketball.c  定义子类覆写父类抽象方法
#include "func.h"

// 定义子类覆写父类抽象方法
void basketball_init(Basketball *game)
{
  printf("\r\n Basketball::init() [Basketball Game Initialized! Start playing.]");
}

void basketball_start(Basketball *game)
{
  printf("\r\n Basketball::start() [Basketball Game Started. Enjoy the game!]");
}

void basketball_end(Basketball *game)
{
  printf("\r\n Basketball::end() [Basketball Game Finished!]");
}

Basketball *basketball_constructor(char *name)
{
  printf("\r\n basketball_constructor() [构建Basketball]");
  GameTemplate *template = game_template_constructor(name);
  Basketball *game = (Basketball *)template;
  game->init = &basketball_init;
  // 如果不覆盖则使用基类的函数
  // game->start = &basketball_start;
  game->end = &basketball_end;
  return game;
}

// football.c 定义子类覆写父类抽象方法
#include "func.h"

// 定义子类覆写父类抽象方法
void football_init(Football *game)
{
  printf("\r\n Football::init() [Football Game Initialized! Start playing.]");
}

void football_start(Football *game)
{
  printf("\r\n Football::start() [Football Game Started. Enjoy the game!]");
}

void football_end(Football *game)
{
  printf("\r\n Football::end() [Football Game Finished!]");
}

Football *football_constructor(char *name)
{
  printf("\r\n football_constructor() [构建Football]");
  GameTemplate *template = game_template_constructor(name);
  Football *game = (Football *)template;
  game->init = &football_init;
  game->start = &football_start;
  game->end = &football_end;
  return game;
}

// tennis.c 定义子类覆写父类抽象方法
#include "func.h"

// 定义子类覆写父类抽象方法
void tennis_init(Tennis *game)
{
  printf("\r\n Tennis::init() [Tennis Game Initialized! Start playing.]");
}

void tennis_start(Tennis *game)
{
  printf("\r\n Tennis::start() [Tennis Game Started. Enjoy the game!]");
}

void tennis_end(Tennis *game)
{
  printf("\r\n Tennis::end() [Tennis Game Finished!]");
}

// 在调用父类play之前,如果要执行自己的行为,也可以覆盖父类方法
void tennis_play(Tennis *game)
{
  // 先执行自己的内容,再调用基类的函数
  printf("\r\n Tennis::play() [Tennis Game Play!]");
  template_play((GameTemplate *)game);
}

Tennis *tennis_constructor(char *name)
{
  printf("\r\n tennis_constructor() [构建Tennis]");
  GameTemplate *template = game_template_constructor(name);
  Tennis *game = (Tennis *)template;
  game->init = &tennis_init;
  game->start = &tennis_start;
  game->end = &tennis_end;
  game->play = &tennis_play;
  return game;
}

测试调用

#include "../src/func.h"

int main(void)
{
  printf("test start:\r\n");
  /**
   * 模板方法模式就是当子类具备类似行为的时候,让子类共用一套流程
   * 创建一个公共模板,确定公用流程和操作动作,子类覆盖具体的动作
   */
  Football *football = football_constructor("football");
  football->play(football);

  printf("\r\n ===");
  Basketball *basketball = basketball_constructor("basketball");
  basketball->play(basketball);

  printf("\r\n ===");
  Tennis *tennis = tennis_constructor("basketball");
  tennis->play(tennis);
}

更多语言版本

不同语言设计模式源码:https://github.com/microwind/design-pattern

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/476063.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ToLua框架

ToLua 是一个用于在 Unity 中为 Lua 提供 C# 语言绑定的框架。通过 ToLua&#xff0c;你可以方便地将 C# 代码暴露给 Lua 脚本&#xff0c;并在 Lua 脚本中调用 C# 类、方法和属性。 更新流程 原理&#xff1a;使用AssetBundle进行资源的更新&#xff0c;而由于lua运行时才编…

架构设计-分布式ID

一、 分布式ID基础 1.背景 1.为什么要引用分布式主键ID&#xff1f; 比如单机 MySQL 数据库&#xff0c;前期因为业务量不大&#xff0c;只是使用单个数据库存数据&#xff0c;后期发现业务量一下子就增长&#xff0c;单机 MySQL 已经不能满足于现在的数据量&#xff0c;单机…

【实战项目开发技术分享】常用的ROS工具与命令

常用的ROS工具介绍 作为机器人领域最为流行的开源框架之一,ROS(Robot Operating System)提供了丰富的工具来支持机器人的开发和部署。下面是一些常用的ROS工具及其功能的介绍: roscore:roscore是ROS的主要进程,它启动ROS Master节点并协调ROS系统中的所有进程。所有ROS节…

NEFU数据库基本操作实验总结

前言 SQL语言集数据定义、数据操纵、数据查询、数据控制功能于一体。 数据定义&#xff1a;create&#xff0c;drop&#xff0c;alter 数据操纵&#xff1a;增(insert into … )&#xff0c;删(delete from …)&#xff0c;改(update … set …) 数据查询&#xff1a;select 数…

如何在 Linux 环境下安装使用 pycharm?介绍一种快捷打开方式

之所以要出这个教程&#xff0c;是想介绍一种更快捷的打开方式。官网上的教程&#xff0c;每次打开都要切换到下载地址&#xff0c;然后输入 ./pycharm.sh 才能运行。 如图&#xff0c;在任意位置打开终端&#xff0c;敲快捷键pc就能打开 pycharm 怎么样&#xff0c;非常方便…

MYSQL进阶01

MYSQL进阶 存储引擎存储引擎的特性MyISAMInnoDBMEMORY 如何选择合适的引擎 存储引擎 MYSQL默认支持多种存储引擎&#xff0c;可以根据用户不同需求选择合适的储存引擎。MYSQL支持的存储引擎包括但不局限于以下几种&#xff08;MyISAM、InnoDB、MEMORY、MERGE…&#xff0c;创建…

【Leetcode -142.环形链表Ⅱ -143.重排链表】

Leetcode Leetcode -142.环形链表ⅡLeetcode - 143.重排链表 Leetcode -142.环形链表Ⅱ 题目&#xff1a;给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 …

CodeRush Ultimate Crack终极版

CodeRush Ultimate Crack终极版 CodeRush Ultimate通过提高生产力&#xff0c;同时消除侵蚀创造力的重复&#xff0c;帮助开发人员在更短的时间内提供更多高质量的功能。它可以帮助您在几秒钟内创建复杂的代码块&#xff0c;并立即扩展代码模板&#xff0c;并在您按逻辑键入、扩…

[架构之路-179]-《软考-系统分析师》-19- 系统可靠性分析与设计 - 故障模型、可靠性模型、可靠性分析

目录 前言&#xff1a; 1 9 . 1 系统可靠性概述 19.1.1 系统故障模型 1. 在信息系统中&#xff0c;故障或错误有如下儿种表现形式&#xff1a; 2. 故障的缘由 3. 故障模型 &#xff08;1&#xff09;逻辑电路级的故障 &#xff08;2&#xff09; 数据结构级的故障 &a…

spass modeler

课时1&#xff1a;SPSS Modeler 简介 本课时一共分为五个模块&#xff0c;分别是Modeler概述、工具安装、窗口说明以及功能介绍和应用案例。相信通过本课时内容的学习&#xff0c;大家将会对SPSS Modeler有个基础的了解. 在学习本节课内容之前&#xff0c;先来看看本节课我们究…

Wi-Fi (-6) 知识点整理

Wi-Fi - 6 知识点整理 2019年IEEE推出IEEE 802.11ax&#xff0c;WiFi联盟&#xff08;WFA&#xff09;称其为WiFi-6 Wi-Fi (Wireless Fidelity) 无线保真&#xff0c;无线兼容性认证 通信技术 商标 商业认证 技术联盟 Wi-Fi 网络基本要素 接入点&#xff08;Access Point&a…

前端存储二:indexedDB

indexedDB 特点&#xff1a;以域名纬度&#xff0c;浏览器大量结构化数据存储方案&#xff0c;运行在浏览器的非关系型数据库。 大小&#xff1a;不会小于 250MB&#xff0c;支持二进制存储。 接口&#xff1a;异步接口&#xff0c;支持事物机制 这里使用网页脚本生成&#x…

【五一创作】【Simulink】采用延时补偿的三相并网逆变器FCS-MPC

&#x1f449; 【Simulink】基于FCS-MPC的三相并网逆变器控制 上一篇博客介绍了FCS-MPC的基本操作&#xff0c;并且以三相并网逆变器为控制对象进行了Simulink仿真。 但实际仿真中没有考虑补偿延时。本篇博客将讨论为什么要考虑延时并进行补偿&#xff0c;最后对此仿真验证。 …

参会记录|全国多媒体取证暨第二届多媒体智能安全学术研讨会(MAS‘2023)

前言&#xff1a;2023年4月8日上午&#xff0c;我与实验室的诸位伙伴们共聚浙江杭州西子湖畔的六通宾馆&#xff0c;参加了为期一天半的全国多媒体取证暨第二届多媒体智能安全学术研讨会&#xff08;MAS’2023&#xff09;。本届学术研讨会由浙江省自然科学基金委员会资助&…

3.2 静态随机存取存储器

学习目标&#xff1a; 学习静态随机存取存储器&#xff08;SRAM&#xff09;的基本原理、结构和工作方式&#xff0c;理解其与动态随机存取存储器&#xff08;DRAM&#xff09;的区别和优缺点&#xff0c;掌握SRAM的性能参数和应用领域&#xff0c;了解SRAM的发展历程和未来趋…

三元操作 三元操作符 if-else / ? :

Python 三元操作符 if-else &#xff0c; 其他语言三元操操作符 ? : 。 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;不仅仅是基础那么简单……地址&#xff1a;h…

【Java】类和对象,封装

目录 1.类和对象的定义 2.关键字new 3.this引用 4.对象的构造及初始化 5.封装 //包的概念 //如何访问 6.static成员 7.代码块 8.对象的打印 1.类和对象的定义 对象&#xff1a;Java中一切皆对象。 类&#xff1a;一般情况下一个Java文件一个类&#xff0c;每一个类…

深度学习的定义和未来发展趋势

深度学习的定义和未来发展趋势 什么是深度学习数学和编程的基础知识深度学习的应用领域深度学习的常见算法和模型训练深度学习模型深度学习的未来 &#x1f3d8;️&#x1f3d8;️个人简介&#xff1a;以山河作礼。 &#x1f396;️&#x1f396;️:Python领域新星创作者&#…

Linux [常见指令 (1)]

Linux常见指令 ⑴ 1. 操作系统1.1什么事操作系统1.2选择指令的原因 2.使用工具3.Linux的指令操作3.1mkdir指令描述:用法:例子 mkdir 目录名例子 mkdir -p 目录1/ 目录2/ 目录3 3.2 touch指令描述:用法:例子 touch 文件 3.2pwd指令描述:用法:例子 pwd 3.4cd指令描述:用法:例子 c…

SQL语句截取字段某指定字符的前半段/后半段内容

最近项目中遇到一个小问题&#xff1a; 需要从数据库中取出对应数据&#xff0c;并根据某个字段中的前半段内容进行排序&#xff0c;搜索资料后得以解决&#xff0c;现将解决方法记录如下&#xff1a; 最初的查询SQL&#xff1a; SELECT file_name,sort FROM base_annexesfil…