go-淺學設計模式隨記

来源:https://www.cnblogs.com/chenjianhui254/archive/2022/12/30/17015061.html
-Advertisement-
Play Games

談起消息隊列,內心還是會有些波瀾。 消息隊列、緩存、分庫分表是高併發解決方案三劍客,而消息隊列是我最喜歡,也是思考最多的技術。我想按照下麵的四個階段分享我與消息隊列的故事,同時也是對我技術成長經歷的回顧。 ...


責任鏈模式

組成:由多個處理器及處理器處理標誌串聯組成

作用:常用於處理流水線事務,利用多個處理器對同一個對象進行處理,可以利用各處理器開關

場景:常見邏輯層處理邏輯:獲取參數、fetch數據、邏輯處理數據、返回參數一系列數據處理

優點:將複雜的流水線處理邏輯簡化為一個個單元,操作較為便捷,可以隨意在處理器之間串聯穿插新處理器

package burden_chain

import "fmt"

/*
   責任鏈模式
   組成:由多個處理器及處理器處理標誌串聯組成
   作用:常用於處理流水線事務,利用多個處理器對同一個對象進行處理,可以利用各處理器開關
   場景:常見的獲取參數、fetch數據、邏輯處理數據、返回參數一系列數據連續化處理
   優點:將複雜的流水線處理邏輯簡化為一個個單元,操作較為便捷,可以隨意在處理器之間串聯穿插新處理器
*/

// CalProcessor 處理器抽象介面
type CalProcessor interface {
   SetNextProcessor(processor CalProcessor)
   ProcessFor(calIdentity *CalIdentity)
}

// CalIdentity 處理對象實體
type CalIdentity struct {
   A          int
   B          int
   sum        int
   hasGetA    bool // GetAProcessor開關:是否獲取到A
   hasGetB    bool // GetBProcessor開關:是否獲取到B
   hasAdd     bool // SumProcessor開關:A與B是否相加
   isComplete bool // CompleteProcessor開關:完成計算
}

// baseCalProcessor 基類實現CalProcessor
type baseCalProcessor struct {
   nextCalProcessor CalProcessor
}

// SetNextProcessor 用於串聯處理器
func (b *baseCalProcessor) SetNextProcessor(processor CalProcessor) {
   b.nextCalProcessor = processor
}

// ProcessFor 用於承接處理器的執行邏輯
func (b *baseCalProcessor) ProcessFor(calIdentity *CalIdentity) {
   if b.nextCalProcessor != nil {
      b.nextCalProcessor.ProcessFor(calIdentity)
   }
}

// GetAProcessor 獲取數字A處理器
type GetAProcessor struct {
   baseCalProcessor
}

func (g *GetAProcessor) ProcessFor(calIdentity *CalIdentity) {
   if !calIdentity.hasGetA {
      fmt.Println("getting number A.")
   }
   fmt.Println("A")
   calIdentity.hasGetA = true
   g.nextCalProcessor.ProcessFor(calIdentity)
}

// GetBProcessor 獲取數字B處理器
type GetBProcessor struct {
   baseCalProcessor
}

func (g *GetBProcessor) ProcessFor(calIdentity *CalIdentity) {
   if !calIdentity.hasGetA {
      fmt.Println("didn't get number A.")
      return
   }
   fmt.Println("B")
   calIdentity.hasGetB = true
   g.nextCalProcessor.ProcessFor(calIdentity)
}

// SumProcessor 加法處理器
type SumProcessor struct {
   baseCalProcessor
}

func (g *SumProcessor) ProcessFor(calIdentity *CalIdentity) {
   if !calIdentity.hasGetA || !calIdentity.hasGetB {
      fmt.Println("didn't get number A or B")
      return
   }
   fmt.Println("A plus B")
   calIdentity.hasAdd = true
   g.nextCalProcessor.ProcessFor(calIdentity)
}

// CompleteProcessor 完成處理器
type CompleteProcessor struct {
   baseCalProcessor
}

func (c *CompleteProcessor) ProcessFor(calIdentity *CalIdentity) {
   if !calIdentity.hasGetA || !calIdentity.hasGetB || !calIdentity.hasAdd {
      fmt.Println("cal not done.")
      return
   }
   fmt.Println("done")
   calIdentity.isComplete = true
   return
}

測試類

package burden_chain

import "testing"

func TestChainResponsibility(t *testing.T) {
   calProcessor := BuildCalProcessorChain()
   calIdentity := &CalIdentity{
      A:          0,
      B:          0,
      sum:        0,
      hasGetA:    false,
      hasGetB:    true,
      hasAdd:     false,
      isComplete: false,
   }
   calProcessor.ProcessFor(calIdentity)
}

// BuildCalProcessorChain: GetAProcessor -> GetBProcessor -> SumProcessor -> CompleteProcessor
func BuildCalProcessorChain() CalProcessor {
   completeCheckNode := &CompleteProcessor{}

   sumCheckNode := &SumProcessor{}
   sumCheckNode.SetNextProcessor(completeCheckNode)

   getBCheckNode := &GetBProcessor{}
   getBCheckNode.SetNextProcessor(sumCheckNode)

   getACheckNode := &GetAProcessor{}
   getACheckNode.SetNextProcessor(getBCheckNode)

   return getACheckNode
}

命令模式

組成:接受者、指令觸發器
作用:將請求方法參數化,將指令抽象,便於在指令與指令之間建立獨立的邏輯操作關係

場景:適用於任務定製需求,比如818活動等等,在特點的時間節點,使用特定的功能需求。

優點:將指令單元化,通過統一的的Execute介面方法進行調用,屏蔽各個請求的差異,便於多命令組裝、回滾,屏蔽各個請求的差異

接受者

package order_pattern

type ReceiverA struct {
   height int
   width  int
}

func (s *ReceiverA) SetHeight(height int) {
   s.height = height
}

func (s *ReceiverA) SetWidth(width int) {
   s.width = width
}

func (s *ReceiverA) Shutdown() string {
   return "shut down this formulation."
}

指令觸發器

package order_pattern

import "fmt"

/*
   命令模式
   組成:接受者、指令觸發器
   作用:將請求方法參數化,將指令抽象,便於在指令與指令之間建立獨立的邏輯操作關係
   優點:將指令單元化,通過統一的的Execute介面方法進行調用,屏蔽各個請求的差異,便於多命令組裝、回滾,屏蔽各個請求的差異
*/

type CalCommand interface {
   Execute() string
}

// CalCircleCommand 計算周長
type CalCircleCommand struct {
   receiver *ReceiverA
}

// 指令將接受者內嵌
func NewCalCircleCommand(receiver *ReceiverA) *CalCircleCommand {
   return &CalCircleCommand{receiver: receiver}
}

// 利用各個指令內置方法,將不同指令的執行過程屏蔽,便於擴展
func (c *CalCircleCommand) Execute() string {
   c.receiver.SetWidth(2)
   c.receiver.SetHeight(3)
   return fmt.Sprintf("the circle of receiver is %.2f", float64(2*(c.receiver.width+c.receiver.height)))
}

// CalAreaCommand 計算面積
type CalAreaCommand struct {
   receiver *ReceiverA
}

func NewCalAreaCommand(receiver *ReceiverA) *CalAreaCommand {
   return &CalAreaCommand{receiver: receiver}
}

func (c *CalAreaCommand) Execute() string {
   c.receiver.SetWidth(2)
   c.receiver.SetHeight(3)
   return fmt.Sprintf("the area of receiver is %.2f", float64(c.receiver.height*c.receiver.width))
}

type CommandInvoker struct {
   calCommand CalCommand
}

func (c *CommandInvoker) SetCommand(calCommand CalCommand) {
   c.calCommand = calCommand
}

func (c *CommandInvoker) ExecuteCommand() string {
   return c.calCommand.Execute()
}

測試類

package order_pattern

import (
   "fmt"
   "testing"
)

func TestOrderPattern(t *testing.T) {
   receiver := new(ReceiverA)
   commandInvoker := new(CommandInvoker)

   circleCommand := NewCalCircleCommand(receiver)
   commandInvoker.SetCommand(circleCommand)
   fmt.Println(commandInvoker.ExecuteCommand())

   areaCommand := NewCalAreaCommand(receiver)
   commandInvoker.SetCommand(areaCommand)
   fmt.Println(commandInvoker.ExecuteCommand())
}

迭代器模式

組成:創建迭代器的工廠方法介面Iterable、迭代器本身本身的介面memberIterator
作用:用於在不暴露集合底層表現形式的情況下遍歷集合中的所有元素,即在迭代器的幫助下,客戶端可以用一個迭代器介面以相似的方法遍歷不同集合中的元素
場景:適用於為迭代遍歷來自兩個及以上不同類型的集合中的元素,無視集合的底層類型,只通過暴露出的Next和HasNext來訪問元素

實體類

package iterator_pattern

import "fmt"

// Member 成員抽象介面
type Member interface {
   Info() string
}

// Teacher 教師實體
type Teacher struct {
   Name    string
   Subject string
}

// NewTeacher 創建教師實體
func NewTeacher(name, subject string) *Teacher {
   return &Teacher{
      Name:    name,
      Subject: subject,
   }
}

// Info 返回教師信息
func (t *Teacher) Info() string {
   return fmt.Sprintf("%s老師負責的科目-%s", t.Name, t.Subject)
}

// Student 學生實體
type Student struct {
   Name     string
   SumScore int
}

// NewStudent 創建學生實體
func NewStudent(name string, score int) *Student {
   return &Student{
      Name:     name,
      SumScore: score,
   }
}

// Info 返回學生信息
func (s *Student) Info() string {
   return fmt.Sprintf("%s同學考試分數:%d", s.Name, s.SumScore)
}

迭代器

package iterator_pattern

/*
   迭代器模式
   組成:創建迭代器的工廠方法介面Iterable、迭代器本身本身的介面memberIterator
   作用:用於在不暴露集合底層表現形式的情況下遍歷集合中的所有元素,即在迭代器的幫助下,客戶端可以用一個迭代器介面以相似的方法遍歷不同集合中的元素
   場景:適用於為迭代遍歷來自兩個及以上不同類型的集合中的元素,無視集合的底層類型,只通過暴露出的Next和HasNext來訪問元素
*/

// Iterator 迭代器抽象介面
type Iterator interface {
   Next() Member
   HasNext() bool
}

// memberIterator 迭代器實現類
type memberIterator struct {
   class *Class
   index int
}

// Next 獲取迭代器中的下一個元素
func (m *memberIterator) Next() Member {
   if m.index == -1 { // 若游標是-1,則返回老師
      m.index++
      return m.class.Teacher
   }

   student := m.class.Students[m.index] // 游標大於等於0,則返回學生
   m.index++
   return student
}

// HasNext 判斷是否存在下一個元素
func (m *memberIterator) HasNext() bool { // 判斷是否還有剩餘需要迭代的元素
   return m.index < len(m.class.Students)
}

// Iterable 可迭代集合介面,實現此介面返回迭代器
type Iterable interface {
   CreateIterator() Iterator
}

// Class 包括班級id、老師和同學
type Class struct {
   Id       int
   Teacher  *Teacher
   Students []*Student
}

// NewClass 根據班級id、老師創建班級
func NewClass(id int, teacherName, subject string) *Class {
   return &Class{
      Id:      id,
      Teacher: NewTeacher(teacherName, subject),
   }
}

// GetClassID 獲取班級id
func (c *Class) GetClassID() int {
   return c.Id
}

// AddStudent 增加學生
func (c *Class) AddStudent(students ...*Student) {
   c.Students = append(c.Students, students...)
}

// CreateIterator 創建班級迭代器
// 迭代器兩要素:班級實體、迭代索引
func (c *Class) CreateIterator() Iterator {
   return &memberIterator{
      class: c,  // 待迭代容器
      index: -1, // 迭代索引初始化為-1,從老師開始迭代
   }
}

測試類

package iterator_pattern

import (
   "fmt"
   "testing"
)

func TestIterator(t *testing.T) {
   class := NewClass(1, "cjh", "CS")
   class.AddStudent(NewStudent("張三", 410),
      NewStudent("李四", 400))

   fmt.Printf("%d班級成員如下:\n", class.GetClassID())
   classIterator := class.CreateIterator()
   for classIterator.HasNext() {
      member := classIterator.Next()
      fmt.Println(member.Info())
   }
}

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

-Advertisement-
Play Games
更多相關文章
  • -- 題圖:蘇州天平山楓葉 現在是 2022 年末,痞子衡又要起筆博文年終總結了,看著 2020 年之前的博文總結缺失,始終覺得缺憾,所以寫下此篇 2016 - 2019 總結合輯。2016 年之前,痞子衡也發表過一些文章,不過沒有持續性,那時候更多是以個人筆記形式留在硬碟里。2016 年是痞子衡正 ...
  • Shell變數 變數是任何一種編程語言都必不可少的組成部分,變數用來存放各種數據。腳本語言在定義變數時通常不需要指明類型,直接賦值就可以,Shell 變數也遵循這個規則。 在 Bash shell 中,每一個變數的值都是字元串,無論你給變數賦值時有沒有使用引號,值都會以字元串的形式存儲。 這意味著, ...
  • 參考資料:RabbitMQ tutorial - "Hello world!" — RabbitMQ 前言 RabbitMQ是一個中間人,它接受和轉發消息。我們可以把它想象成一個郵局:當你把郵件投入郵箱的時候,你可以確信它最終會被投遞到收件人的手中。RabbitMQ就是那個郵箱、郵局和郵差。區別就在 ...
  • 一:背景 1.講故事 最近給一位朋友做 SQL 慢語句 優化,花了些時間調優,遺憾的是 SQLSERVER 非源碼公開,玩起來不是那麼順利,不過從這次經歷中我覺得明年的一個重大任務就是好好研究一下它,爭取在 SQLSERVER 性能優化上做一些成績,哈哈! 個人覺得要想深入研究 SQLSERVER, ...
  • 摘要:MRS IoTDB,它是華為FusionInsight MRS大數據套件中的時序資料庫產品,在深度參與Apache IoTDB社區開源版的基礎上推出的高性能企業級時序資料庫產品。 本文分享自華為雲社區《工業數據分析為什麼要用FusionInsight MRS IoTDB?》,作者:高深廣 。 ...
  • 簡介 CloudCanal 實現了對 Online DDL 工具如 GH-OST 和 PT-OSC 的支持,保證了對端實時同步源端的 Online DDL 操作。 本文以 MySQL -> MySQL 同步鏈路使用 GH-OST 為例,介紹 CloudCanal 是如何支持實時同步 GH-OST 產 ...
  • 統計主題 需求指標【ADS】輸出方式計算來源來源層級 訪客【DWS】pv可視化大屏page_log 直接可求dwd UV(DAU)可視化大屏需要用 page_log 過濾去重dwm UJ 跳出率可視化大屏需要通過 page_log 行為判斷dwm 進入頁面數可視化大屏需要識別開始訪問標識dwd 連續 ...
  • 前言 Angular 按照既定的發版計劃在 11 月中旬發佈了 v15 版本。推遲了一個月(幾乎每個版本都是這個節奏😳),Ng-Matero 也終於更新到了 v15。其實 Ng-Matero 本身的更新非常簡單,但是同步維護的 Material Extensions 這個庫要先於 Ng-Mater ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...