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

Posted 刀法如飞-专注算法与设计模式

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板方法设计模式详解C/Java/JS/Go/Python/TS不同语言实现相关的知识,希望对你有一定的参考价值。

简介

模板方法模式(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

C#设计模式详解——Template Method(模板方法)

文章目录

C#设计模式(1)——Template Method(模板方法)

一、概念

动机:

在软件的构建过程中,对于某一项任务,他常常有稳定的整体操作结构,但是各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现

解决方法:

定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中。

缘由:

Template Method 是的子类可以不改变(复用)一个算法的接口即可重定义(overrider)该算法的某些特定步骤

应用场景:

通过以上的描述实质上,其实类模板方法这种设计模式说白了就是抽出其他类的共性,但是前提是我们需要根据需求的实现来选择是否通过这种设计模式来实现。假设我们的需求只会用到一个类的实现步骤以及实现过程,那我们就没有必要选择一开始就通过模板方法的方式来做。设计模式的要义在于我们只有在做到需求变化的同时,现有的功能逻辑以及不符合变化的需求了,我们才会考虑去利用设计模式来减少繁杂的代码。

之前有在一个博客上看到过一篇文章,忘记是哪位博主发的了,大概的步骤就是将一个游戏的实现固有步骤通过模板方法的方式来做;

二、代码案例

Game.cs
抽象游戏类

 	/// <summary>
    /// 抽象游戏类
    /// </summary>
    public abstract class Game
    
        //每款游戏都要投币,子类不能重写(该部分为稳定的模块)
        public void InsertCoins()
        
            Console.WriteLine("往游戏机里面投币...");
        
        public abstract void InitGame();
        public abstract void StartGame();
        public abstract void EndGame();

        public void Play()
        
            //投币
            InsertCoins();
            //初始化游戏
            InitGame();
            //开始游戏
            StartGame();
            //游戏结束
            EndGame();
        

    


CrossFileGame .cs

 /// <summary>
    /// 穿越火线游戏类
    /// </summary>
    public class CrossFileGame : Game
    
        public override void InitGame()
        
            Console.WriteLine("初始化穿越火线游戏..");
        

        public override void StartGame()
        
            Console.WriteLine("开始穿越火线游戏..");
        

        public override void EndGame()
        
            Console.WriteLine("结束穿越火线游戏..");
        

    

YXLMGame .cs

 /// <summary>
    /// 英雄联盟游戏类
    /// </summary>
    public class YXLMGame : Game
    
        public override void InitGame()
        
            Console.WriteLine("初始化英雄联盟游戏..");
        
        public override void StartGame()
        
            Console.WriteLine("开始英雄联盟游戏..");
        
        public override void EndGame()
        
            Console.WriteLine("结束英雄联盟游戏..");
        
    
/// <summary>
    /// 游戏主循环类
    /// </summary>
    class Program
    
        static void Main(string[] args)
        
            Game yxmlGame = new YXLMGame();
            yxmlGame.Play();
            Console.WriteLine();

            Game cfGame = new CrossFileGame();
            cfGame.Play();
        
    

运行结果:

三、类图关系

类的实现关系如图:

看到类图我们发现,我们在实现该流程的时候我们主要是将两个游戏中的共性交由Game抽象类来处理,同时我们也将固有的相同步骤交由抽象类来调用;

而此时就呼应了 定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中这一过程;

作者:ProMer_Wang

链接:https://blog.csdn.net/qq_43801020/article/details/126277540

本文为ProMer_Wang的原创文章,著作权归作者所有,转载请注明原文出处,欢迎转载!

以上是关于模板方法设计模式详解C/Java/JS/Go/Python/TS不同语言实现的主要内容,如果未能解决你的问题,请参考以下文章

C#设计模式详解——Template Method(模板方法)

C#设计模式详解——Template Method(模板方法)

设计模式之模板方法模式(Template Method)详解及代码示例

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

AbstractQueuedSynchronizer 详解

C++11程序设计要点总结-模板机制详解