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
  • C#TMS系統代碼-基礎頁面BaseCity學習 本人純新手,剛進公司跟領導報道,我說我是java全棧,他問我會不會C#,我說大學學過,他說這個TMS系統就給你來管了。外包已經把代碼給我了,這幾天先把增刪改查的代碼背一下,說不定後面就要趕鴨子上架了 Service頁面 //using => impo ...
  • 委托與事件 委托 委托的定義 委托是C#中的一種類型,用於存儲對方法的引用。它允許將方法作為參數傳遞給其他方法,實現回調、事件處理和動態調用等功能。通俗來講,就是委托包含方法的記憶體地址,方法匹配與委托相同的簽名,因此通過使用正確的參數類型來調用方法。 委托的特性 引用方法:委托允許存儲對方法的引用, ...
  • 前言 這幾天閑來沒事看看ABP vNext的文檔和源碼,關於關於依賴註入(屬性註入)這塊兒產生了興趣。 我們都知道。Volo.ABP 依賴註入容器使用了第三方組件Autofac實現的。有三種註入方式,構造函數註入和方法註入和屬性註入。 ABP的屬性註入原則參考如下: 這時候我就開始疑惑了,因為我知道 ...
  • C#TMS系統代碼-業務頁面ShippingNotice學習 學一個業務頁面,ok,領導開完會就被裁掉了,很突然啊,他收拾東西的時候我還以為他要旅游提前請假了,還在尋思為什麼回家連自己買的幾箱飲料都要叫跑腿帶走,怕被偷嗎?還好我在他開會之前拿了兩瓶芬達 感覺感覺前面的BaseCity差不太多,這邊的 ...
  • 概述:在C#中,通過`Expression`類、`AndAlso`和`OrElse`方法可組合兩個`Expression<Func<T, bool>>`,實現多條件動態查詢。通過創建表達式樹,可輕鬆構建複雜的查詢條件。 在C#中,可以使用AndAlso和OrElse方法組合兩個Expression< ...
  • 閑來無聊在我的Biwen.QuickApi中實現一下極簡的事件匯流排,其實代碼還是蠻簡單的,對於初學者可能有些幫助 就貼出來,有什麼不足的地方也歡迎板磚交流~ 首先定義一個事件約定的空介面 public interface IEvent{} 然後定義事件訂閱者介面 public interface I ...
  • 1. 案例 成某三甲醫預約系統, 該項目在2024年初進行上線測試,在正常運行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (curren ...
  • 背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...