Java 中裝飾者模式與策略模式在埋點系統中的應用

前言

在軟件開發中,裝飾者模式和策略模式是兩種常用的設計模式,它們在特定的業務場景下能夠發揮巨大的作用。本文將通過一個實際的埋點系統案例,探討如何在 Java 中運用裝飾者模式和策略模式,以及如何結合工廠方法模式來優化代碼結構。

業務場景分析

隨著互聯網的發展,用戶行為分析變得越來越重要,而埋點技術是實現用戶行為分析的關鍵手段之一。埋點系統需要記錄用戶在應用中的各種操作行為,如點擊、瀏覽、提交等,以便后續進行數據分析和業務決策。

假設我們正在開發一個在線教育平臺,需要實現以下埋點功能:

  1. 點擊埋點:記錄用戶點擊的位置。

  2. 課程埋點:記錄用戶點擊的課程信息。

  3. 任務埋點:記錄用戶點擊的任務信息。

這些埋點功能需要根據不同的業務場景進行動態組合,例如在課程頁面的點擊操作需要記錄點擊位置和課程信息,而在任務頁面的點擊操作需要記錄點擊位置和任務信息。

裝飾者模式的應用

裝飾者模式允許我們在不修改原有代碼的基礎上,動態地給對象添加職責。它由以下幾部分組成:

  • Component:定義對象的接口。

  • Concrete Component:實現 Component 接口的具體對象。

  • Decorator:維護一個對 Component 對象的引用,并定義與 Component 接口相同的接口。

  • Concrete Decorator:實現 Decorator 接口,負責給 Component 對象添加特定的職責。

實現埋點功能

// Component 接口
public interface SaveMessage {void saveMessage(PointSaveBean pointSaveBean, PointSaveRequest pointSaveRequest);
}// Concrete Component:基礎點擊埋點
public class CommonClickPoint implements SaveMessage {@Overridepublic void saveMessage(PointSaveBean pointSaveBean, PointSaveRequest pointSaveRequest) {pointSaveBean.setClickLocation(pointSaveRequest.getClickLocation());}
}// Decorator 抽象類
public abstract class AddPointMessageService implements SaveMessage {protected SaveMessage saveMessage;public AddPointMessageService(SaveMessage saveMessage) {this.saveMessage = saveMessage;}@Overridepublic void saveMessage(PointSaveBean pointSaveBean, PointSaveRequest pointSaveRequest) {saveMessage.saveMessage(pointSaveBean, pointSaveRequest);}
}// Concrete Decorator:課程埋點
public class CourseClickPoint extends AddPointMessageService {public CourseClickPoint(SaveMessage saveMessage) {super(saveMessage);}@Overridepublic void saveMessage(PointSaveBean pointSaveBean, PointSaveRequest pointSaveRequest) {super.saveMessage(pointSaveBean, pointSaveRequest);pointSaveBean.setCourseId(pointSaveRequest.getCourseId());}
}// Concrete Decorator:任務埋點
public class TaskClickPoint extends AddPointMessageService {public TaskClickPoint(SaveMessage saveMessage) {super(saveMessage);}@Overridepublic void saveMessage(PointSaveBean pointSaveBean, PointSaveRequest pointSaveRequest) {super.saveMessage(pointSaveBean, pointSaveRequest);pointSaveBean.setTaskId(pointSaveRequest.getTaskId());}
}

客戶端代碼

public class CommonMain {public static void main(String[] args) {// 初始化埋點類型列表List<PointSaveType> types = Arrays.asList(PointSaveType.TASK, PointSaveType.COURSE);// 初始化埋點保存對象PointSaveBean pointSaveBean = new PointSaveBean();// 初始化埋點請求對象PointSaveRequest pointSaveRequest = PointSaveRequest.builder().pointSaveTypeList(types).clickLocation("右上角落").courseId("英語").taskId("任務1").build();// 初始化基礎保存邏輯SaveMessage saveMessage = new CommonClickPoint();saveMessage.saveMessage(pointSaveBean, pointSaveRequest);System.out.println("基礎埋點保存數據: " + pointSaveBean);// 根據埋點類型動態添加保存邏輯for (PointSaveType type : types) {if (type == PointSaveType.COURSE) {saveMessage = new CourseClickPoint(saveMessage);} else if (type == PointSaveType.TASK) {saveMessage = new TaskClickPoint(saveMessage);}saveMessage.saveMessage(pointSaveBean, pointSaveRequest);}// 打印最終埋點數據System.out.println("最終埋點保存數據: " + pointSaveBean);}
}

策略模式的應用

策略模式定義了一系列算法,并將每個算法封裝到具有共同接口的獨立類中,使它們可以互相替換。當埋點邏輯之間存在復雜的組合關系時,結合策略模式可以更好地管理這些組合邏輯。

實現埋點功能

// 策略接口
public interface PointSaveStrategy {void save(PointSaveBean pointSaveBean, PointSaveRequest pointSaveRequest);
}// 具體策略:點擊埋點
public class ClickPointSaveStrategy implements PointSaveStrategy {@Overridepublic void save(PointSaveBean pointSaveBean, PointSaveRequest pointSaveRequest) {pointSaveBean.setClickLocation(pointSaveRequest.getClickLocation());}
}// 具體策略:課程埋點
public class CoursePointSaveStrategy implements PointSaveStrategy {@Overridepublic void save(PointSaveBean pointSaveBean, PointSaveRequest pointSaveRequest) {pointSaveBean.setCourseId(pointSaveRequest.getCourseId());}
}// 具體策略:任務埋點
public class TaskPointSaveStrategy implements PointSaveStrategy {@Overridepublic void save(PointSaveBean pointSaveBean, PointSaveRequest pointSaveRequest) {pointSaveBean.setTaskId(pointSaveRequest.getTaskId());}
}// 策略上下文
public class PointSaveStrategyContext {private List<PointSaveStrategy> strategies = new ArrayList<>();public void addStrategy(PointSaveStrategy strategy) {strategies.add(strategy);}public void execute(PointSaveBean pointSaveBean, PointSaveRequest pointSaveRequest) {for (PointSaveStrategy strategy : strategies) {strategy.save(pointSaveBean, pointSaveRequest);}}
}// 策略配置
public class PointSaveStrategyConfig {private static final Map<PointSaveType, PointSaveStrategy> STRATEGY_MAP = new HashMap<>();static {STRATEGY_MAP.put(PointSaveType.CLICK, new ClickPointSaveStrategy());STRATEGY_MAP.put(PointSaveType.COURSE, new CoursePointSaveStrategy());STRATEGY_MAP.put(PointSaveType.TASK, new TaskPointSaveStrategy());}public static PointSaveStrategy getStrategy(PointSaveType type) {return STRATEGY_MAP.getOrDefault(type, null);}
}

客戶端代碼

public class CommonMain {public static void main(String[] args) {// 初始化埋點類型列表List<PointSaveType> types = Arrays.asList(PointSaveType.TASK, PointSaveType.COURSE);// 初始化埋點保存對象PointSaveBean pointSaveBean = new PointSaveBean();// 初始化埋點請求對象PointSaveRequest pointSaveRequest = PointSaveRequest.builder().pointSaveTypeList(types).clickLocation("右上角落").courseId("英語").taskId("任務1").build();// 創建策略上下文PointSaveStrategyContext context = new PointSaveStrategyContext();// 添加基礎策略context.addStrategy(new ClickPointSaveStrategy());// 根據埋點類型動態添加策略for (PointSaveType type : types) {PointSaveStrategy strategy = PointSaveStrategyConfig.getStrategy(type);if (strategy != null) {context.addStrategy(strategy);}}// 執行所有策略context.execute(pointSaveBean, pointSaveRequest);// 打印最終埋點數據System.out.println("最終埋點保存數據: " + pointSaveBean);}
}

工廠方法模式的結合

為了進一步簡化客戶端代碼,我們可以引入工廠方法模式來創建裝飾者對象。

// 工廠類
public class PointSaveDecoratorFactory {public static SaveMessage getDecorator(PointSaveType type, SaveMessage saveMessage) {switch (type) {case COURSE:return new CourseClickPoint(saveMessage);case TASK:return new TaskClickPoint(saveMessage);default:System.out.println("未知的埋點類型: " + type);return saveMessage;}}
}

客戶端代碼優化

public class CommonMain {public static void main(String[] args) {// 初始化埋點類型列表List<PointSaveType> types = Arrays.asList(PointSaveType.TASK, PointSaveType.COURSE);// 初始化埋點保存對象PointSaveBean pointSaveBean = new PointSaveBean();// 初始化埋點請求對象PointSaveRequest pointSaveRequest = PointSaveRequest.builder().pointSaveTypeList(types).clickLocation("右上角落").courseId("英語").taskId("任務1").build();// 初始化基礎保存邏輯SaveMessage saveMessage = new CommonClickPoint();saveMessage.saveMessage(pointSaveBean, pointSaveRequest);System.out.println("基礎埋點保存數據: " + pointSaveBean);// 根據埋點類型動態添加保存邏輯for (PointSaveType type : types) {saveMessage = PointSaveDecoratorFactory.getDecorator(type, saveMessage);saveMessage.saveMessage(pointSaveBean, pointSaveRequest);}// 打印最終埋點數據System.out.println("最終埋點保存數據: " + pointSaveBean);}
}

總結

在實際的開發過程中,合理地運用設計模式能夠使我們的代碼更加靈活、可維護和可擴展。裝飾者模式適合用于在運行時動態地給對象添加職責,而策略模式則適合用于管理多種算法或行為的組合。通過結合工廠方法模式,我們可以進一步簡化客戶端代碼,使系統更加模塊化和易于使用。

通過本文的示例,我們看到了裝飾者模式和策略模式在埋點系統中的有效應用。這些設計模式不僅解決了實際的業務問題,還為我們提供了應對復雜需求變化的優雅解決方案。在未來的開發中,我們可以根據具體的需求場景,靈活地選擇和結合不同的設計模式,以構建高質量的軟件系統。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/74552.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/74552.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/74552.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【3-22 list 詳解STL C++ 】

先看代碼&#xff0c;常用的就是代碼中有的那些 #include <bits/stdc.h> using namespace std; int main() {list<int> mylist;for(int i0;i<5;i){mylist.push_back(i);//TODO}for(const auto&i:mylist)cout<<i<<\n;//fanzhuanreverse(mylist.…

田間機器人幼苗視覺檢測與護苗施肥裝置研究(大綱)

田間機器人幼苗視覺檢測與護苗施肥裝置研究 基于多光譜視覺與精準施肥的農業機器人系統設計 第一章 緒論 1.1 研究背景與意義 農業智能化需求&#xff1a; 傳統幼苗檢測依賴人工&#xff0c;效率低且易遺漏弱苗/病苗施肥不精準導致資源浪費和環境污染 技術挑戰&#xff1a;…

如何在Linux CentOS上安裝和配置Redis

如何在Linux CentOS上安裝和配置Redis 大家好&#xff0c;我是曾續緣。歡迎來到本教程&#xff01;今天我將向您介紹在Linux CentOS上安裝和配置Redis的詳細步驟。Redis是一個高性能的鍵值存儲系統&#xff0c;常用于緩存、消息隊列和數據持久化等應用場景。讓我們一起開始吧&…

requests庫post方法怎么傳params類型的參數

在使用 requests 庫的 post 方法時&#xff0c;params 類型的參數通常用于在 URL 中作為查詢字符串傳遞。這與 data 或 json 參數不同&#xff0c;后者是放在請求體中的。下面詳細介紹如何在使用 post 方法時傳遞 params 參數。 使用 params 參數 params 參數接受一個字典或包…

C++常見問題與思考

TLS&#xff08;線程本地存儲&#xff09;原理 線程本地存儲&#xff08;Thread Local Storage&#xff0c;TLS&#xff09;是一種機制&#xff0c;它允許每個線程擁有自己獨立的變量實例&#xff0c;這些變量的生命周期與線程相同。也就是說&#xff0c;不同線程對同一個 TLS…

如何快速下載并安裝 Postman?

從下載、安裝、啟動 Postman 這三個方面為大家詳細講解下載安裝 Postman 每一步操作&#xff0c;幫助初學者快速上手。 Postman 下載及安裝教程(2025最新)

使用Gitee Go流水線部署個人項目到服務器指南

使用Gitee Go流水線部署個人項目到服務器指南 前言&#xff01;&#xff01;&#xff01; 本文解決的問題&#xff1a; 你有一臺ECS服務器&#xff0c;你在上面部署了一個Java服務也就是一個jar&#xff0c;你覺著你每次手動本地打包&#xff0c;上傳&#xff0c;在通過命令去…

Linux第一節:Linux系統編程入門指南

摘要 本文面向Linux初學者&#xff0c;系統講解操作系統核心概念、Shell命令實戰、權限管理精髓及目錄結構解析。通過思維導圖命令示例原理解析的方法&#xff0c;幫助開發者快速構建Linux知識體系&#xff0c;掌握生產環境必備技能。 一、Linux的前世今生&#xff1a;從實驗室…

【Linux 維測專欄 5 -- linux pstore 使用介紹】

文章目錄 Linux pstore 功能簡介1. pstore 概述2. pstore 的核心功能3. pstore 的工作原理4. pstore 的使用示例5. pstore 的優勢6. 典型應用場景配置示例1)DTS配置2)config配置運行測試及log問題小結Linux pstore 功能簡介 1. pstore 概述 pstore(Persistent Storage)是…

在 ASP .NET Core 9.0 中使用 Scalar 創建漂亮的 API 文檔

示例代碼&#xff1a;https://download.csdn.net/download/hefeng_aspnet/90407900 Scalar 是一款可幫助我們為 API 創建精美文檔的工具。與感覺有些過時的默認 Swagger 文檔不同&#xff0c;Scalar 為 API 文檔提供了全新而現代的 UI。其簡潔的設計讓開發人員可以輕松找到測試…

Rabbitmq消息被消費時拋異常,進入Unacked 狀態,進而導致消費者不斷嘗試消費(下)

一、消費流程圖 消息在消費出現異常的時候&#xff0c;將一直保留在消息隊列&#xff0c;所以你會看到以下奇怪的現象&#xff1a; 消息隊列僅有5個消息&#xff0c; 投遞速度也非常快&#xff0c;結果卻一直無法消費掉。 二、重試策略 重試機制的使用場景&#xff1a;重試機制…

【STM32】知識點介紹二:GPIO引腳介紹

文章目錄 一、概述二、GPIO的工作模式三、寄存器編程 一、概述 GPIO&#xff08;英語&#xff1a;General-purpose input/output&#xff09;,即通用I/O(輸入/輸出)端口&#xff0c;是STM32可控制的引腳。STM32芯片的GPIO引腳與外部設備連接起來&#xff0c;可實現與外部通訊、…

JavaScript流程控制精講(二)運算符與循環實戰

JavaScript流程控制精講&#xff08;二&#xff09;運算符與循環實戰 學習目標&#xff1a;掌握條件判斷與循環控制&#xff0c;實現基礎業務邏輯 核心要點&#xff1a;運算符優先級 | 短路運算 | 循環優化 | 項目實戰 一、運算符進階技巧 1.1 算術運算符 console.log(5 % 3)…

如何在IPhone 16Pro上運行python文件?

在 iPhone 16 Pro 上運行 Python 文件需要借助第三方工具或遠程服務&#xff0c;以下是具體實現方法和步驟&#xff1a; 一、本地運行方案&#xff08;無需越獄&#xff09; 使用 Python 編程類 App 以下應用可在 App Store 下載&#xff0c;支持直接在 iPhone 上編寫并運行 …

【趙渝強老師】達夢數據庫的數據庫對象

達夢數據庫中包含各種數據庫對象&#xff0c;主要分為兩大類型&#xff1a;基本數據庫對象和復雜數據庫對象。下面分別進行介紹。 視頻講解如下 【趙渝強老師】達夢數據庫的數據庫對象 一、 基本數據庫對象 常見的基本數據庫對象有&#xff1a;表、索引、視圖、序列、同義詞等…

【每日算法】Day 6-1:哈希表從入門到實戰——高頻算法題(C++實現)

摘要 &#xff1a;掌握高頻數據結構&#xff01;今日深入解析哈希表的核心原理與設計實現&#xff0c;結合沖突解決策略與大廠高頻真題&#xff0c;徹底掌握O(1)時間復雜度的數據訪問技術。 一、哈希表核心思想 哈希表&#xff08;Hash Table&#xff09; 是一種基于鍵值對的…

LeetCode 第29題、30題

LeetCode 第29題&#xff1a;兩數相除 題目描述 給你兩個整數&#xff0c;被除數dividend和除數divisor。將兩數相除&#xff0c;要求不使用乘法、除法和取余運算。整數除法應該向零截斷&#xff0c;也就是截去其小數部分。例如&#xff0c;8.345將被截斷為8&#xff0c;-2.733…

26考研——樹與二叉樹_樹、森林(5)

408答疑 文章目錄 二、樹、森林樹的基本概念樹的定義和特性樹的定義樹的特性 基本術語樹的基本術語和概念祖先、子孫、雙親、孩子、兄弟和堂兄弟結點的層次、度、深度和高度樹的度和高度分支結點和葉結點有序樹和無序樹路徑和路徑長度 森林的基本術語和概念森林的定義森林與樹的…

【HarmonyOS Next之旅】DevEco Studio使用指南(六)

目錄 1 -> 在模塊中添加Ability 1.1 -> Stage模型添加UIAbility 1.1.1 -> 在模塊中添加UIAbility 1.1.2 -> 在模塊中添加Extension Ability 2 -> 創建服務卡片 2.1 -> 概述 2.2 -> 使用約束 2.3 -> 創建服務卡片 2.4 -> 創建動態/靜態卡片…

Langchain 多模態輸入和格式化輸出

多模態輸入 圖片處理&#xff08;最高頻&#xff09; 1.1 URL形式&#xff08;推薦大文件&#xff09; from langchain.schema import HumanMessage from langchain.chat_models import ChatOpenAIchat ChatOpenAI(model"gpt-4-vision-preview")message HumanMes…