【模板方法設計模式詳解】C/Java/JS/Go/Python/TS不同語言實現

来源:https://www.cnblogs.com/letjs/archive/2023/04/29/17364548.html
-Advertisement-
Play Games

簡介 模板方法模式(Template Method Pattern)也叫模板模式,是一種行為型模式。它定義了一個抽象公開類,包含基本的演算法骨架,而將一些步驟延遲到子類中,模板方法使得子類可以不改變演算法的結構,只是重定義該演算法的某些特定步驟。不同的子類以不同的方式實現這些抽象方法,從而對剩餘的邏輯有不 ...


簡介

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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 開心一刻 中午和哥們一起喝茶 哥們說道:晚上喝酒去啊 我:不去,我女朋友過生日 哥們瞪大眼睛看著我:你有病吧,充氣的過什麼生日 我生氣到:有特麽生產日期的好吧 需求背景 系統對接了外部系統,調用外部系統的介面需要付費,一個介面一次調用付費 0.03 元 同一個月內,同一個介面最高付費 25 元 統計 ...
  • 最近遇到公司的一個項目,需要將多張圖片合併成一個播放的視頻,找了很多資料和嘗試了工具,遇到很多的坑,這裡記下來,希望大家也能順利解決遇到的問題。 合併視頻,主要可以借用OpenCV 和 ffmpeg,這裡是嘗試用ffmpeg.exe的工具去實現圖片文件合併成視頻。 輸入存儲視頻文件的路徑,通過Pro ...
  • 書寫識別,網上的大佬們都有輸出。 書寫識別存在的2個問題: 直接拿官網的案例(將 Windows Ink 筆劃識別為文本和形狀 - Windows apps | Microsoft Learn),會發現輸出準確度不高。 另外如果書寫過快,片語識別也是個問題,畢竟無法準確分割字之間的筆跡。 我結合之前 ...
  • .Net Core在調用其他服務時,調用通常使用HttpClient,而HttpClient預設使用HTTP/1.1 。 配置 HttpClient 以使用 HTTP/2 h2 連接 自 .NET Core 3.0 發佈以來, .NET 開發人員可以使用 HttpClient 啟用 HTTP/2 。 ...
  • 本文為大家介紹使用 .NET Core部署到Linux伺服器的方法,通過本文你將瞭解到Linux在虛擬機下的安裝、Xshell,Xftp的使用方法、git在linux下的交互使用以及.net core在linux下的發佈與運行全過程,本文皆在總結了一些經驗與筆記在部署過程中遇到的一些問題,同時分享給... ...
  • 最近在開發用的台式機上啟用了 Windows 的 Hyper-V 虛擬化功能,利用虛擬機運行了一臺 Windows Server 2022 和 一臺 Ubuntu Server,為了方便別的機器直接訪問這兩台虛擬機,所以網路採用了外部網路橋接的模式,讓虛擬機和物理機保持在了同一網段。 為了實現在這一 ...
  • ==資料庫==1、創建資料庫create database [IF NOT EXISTS] 資料庫名; 2、刪除資料庫drop database [IF EXISTS] 資料庫名; 3、切換資料庫select database(); 4、查詢資料庫show databases; —————————— ...
  • 1、四層結構 viewer --> datasources(DataSourceCollection類型) --> datasource --> entities(EntityCollection類型) --> entity 需要學習的方向是:只需要註意每個層與層之間的關係和entity實例如何創建 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...