国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【轉(zhuǎn)存】Go語言設(shè)計(jì)模式

這篇具有很好參考價(jià)值的文章主要介紹了【轉(zhuǎn)存】Go語言設(shè)計(jì)模式。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

導(dǎo)語| 設(shè)計(jì)模式是針對軟件設(shè)計(jì)中常見問題的工具箱,其中的工具就是各種經(jīng)過實(shí)踐驗(yàn)證的解決方案。即使你從未遇到過這些問題,了解模式仍然非常有用,因?yàn)樗苤笇?dǎo)你如何使用面向?qū)ο蟮脑O(shè)計(jì)原則來解決各種問題,提高開發(fā)效率,降低開發(fā)成本;本文囊括了GO語言實(shí)現(xiàn)的經(jīng)典設(shè)計(jì)模式示例,每個(gè)示例都精心設(shè)計(jì),力求符合模式結(jié)構(gòu),可作為日常編碼參考,同時(shí)一些常用的設(shè)計(jì)模式融入了開發(fā)實(shí)踐經(jīng)驗(yàn)總結(jié),幫助大家在平時(shí)工作中靈活運(yùn)用。

【轉(zhuǎn)存】Go語言設(shè)計(jì)模式

責(zé)任鏈模式

(一)概念

責(zé)任鏈模式是一種行為設(shè)計(jì)模式, 允許你將請求沿著處理者鏈進(jìn)行發(fā)送。收到請求后,每個(gè)處理者均可對請求進(jìn)行處理,或?qū)⑵鋫鬟f給鏈上的下個(gè)處理者。

該模式允許多個(gè)對象來對請求進(jìn)行處理,而無需讓發(fā)送者類與具體接收者類相耦合。鏈可在運(yùn)行時(shí)由遵循標(biāo)準(zhǔn)處理者接口的任意處理者動態(tài)生成。

一般意義上的責(zé)任鏈模式是說,請求在鏈上流轉(zhuǎn)時(shí)任何一個(gè)滿足條件的節(jié)點(diǎn)處理完請求后就會停止流轉(zhuǎn)并返回,不過還可以根據(jù)不同的業(yè)務(wù)情況做一些改進(jìn):

  • 請求可以流經(jīng)處理鏈的所有節(jié)點(diǎn),不同節(jié)點(diǎn)會對請求做不同職責(zé)的處理;
  • 可以通過上下文參數(shù)保存請求對象及上游節(jié)點(diǎn)的處理結(jié)果,供下游節(jié)點(diǎn)依賴,并進(jìn)一步處理;
  • 處理鏈可支持節(jié)點(diǎn)的異步處理,通過實(shí)現(xiàn)特定接口判斷,是否需要異步處理;
  • 責(zé)任鏈對于請求處理節(jié)點(diǎn)可以設(shè)置停止標(biāo)志位,不是異常,是一種滿足業(yè)務(wù)流轉(zhuǎn)的中斷;
  • 責(zé)任鏈的拼接方式存在兩種,一種是節(jié)點(diǎn)遍歷,一個(gè)節(jié)點(diǎn)一個(gè)節(jié)點(diǎn)順序執(zhí)行;另一種是節(jié)點(diǎn)嵌套,內(nèi)層節(jié)點(diǎn)嵌入在外層節(jié)點(diǎn)執(zhí)行邏輯中,類似遞歸,或者“回”行結(jié)構(gòu);
  • 責(zé)任鏈的節(jié)點(diǎn)嵌套拼接方式多被稱為攔截器鏈或者過濾器鏈,更易于實(shí)現(xiàn)業(yè)務(wù)流程的切面,比如監(jiān)控業(yè)務(wù)執(zhí)行時(shí)長,日志輸出,權(quán)限校驗(yàn)等;

(二)示例

本示例模擬實(shí)現(xiàn)機(jī)場登機(jī)過程,第一步辦理登機(jī)牌,第二步如果有行李,就辦理托運(yùn),第三步核實(shí)身份,第四步安全檢查,第五步完成登機(jī);其中行李托運(yùn)是可選的,其他步驟必選,必選步驟有任何不滿足就終止登機(jī);旅客對象作為請求參數(shù)上下文,每個(gè)步驟會根據(jù)旅客對象狀態(tài)判斷是否處理或流轉(zhuǎn)下一個(gè)節(jié)點(diǎn);

(三)登機(jī)過程

package chainofresponsibility

import "fmt"

// BoardingProcessor 登機(jī)過程中,各節(jié)點(diǎn)統(tǒng)一處理接口
type BoardingProcessor interface {
  SetNextProcessor(processor BoardingProcessor)
  ProcessFor(passenger *Passenger)
}

// Passenger 旅客
type Passenger struct {
  name                  string // 姓名
  hasBoardingPass       bool   // 是否辦理登機(jī)牌
  hasLuggage            bool   // 是否有行李需要托運(yùn)
  isPassIdentityCheck   bool   // 是否通過身份校驗(yàn)
  isPassSecurityCheck   bool   // 是否通過安檢
  isCompleteForBoarding bool   // 是否完成登機(jī)
}

// baseBoardingProcessor 登機(jī)流程處理器基類
type baseBoardingProcessor struct {
  // nextProcessor 下一個(gè)登機(jī)處理流程
  nextProcessor BoardingProcessor
}

// SetNextProcessor 基類中統(tǒng)一實(shí)現(xiàn)設(shè)置下一個(gè)處理器方法
func (b *baseBoardingProcessor) SetNextProcessor(processor BoardingProcessor) {
  b.nextProcessor = processor
}

// ProcessFor 基類中統(tǒng)一實(shí)現(xiàn)下一個(gè)處理器流轉(zhuǎn)
func (b *baseBoardingProcessor) ProcessFor(passenger *Passenger) {
  if b.nextProcessor != nil {
    b.nextProcessor.ProcessFor(passenger)
  }
}

// boardingPassProcessor 辦理登機(jī)牌處理器
type boardingPassProcessor struct {
  baseBoardingProcessor // 引用基類
}

func (b *boardingPassProcessor) ProcessFor(passenger *Passenger) {
  if !passenger.hasBoardingPass {
    fmt.Printf("為旅客%s辦理登機(jī)牌;\n", passenger.name)
    passenger.hasBoardingPass = true
  }
  // 成功辦理登機(jī)牌后,進(jìn)入下一個(gè)流程處理
  b.baseBoardingProcessor.ProcessFor(passenger)
}

// luggageCheckInProcessor 托運(yùn)行李處理器
type luggageCheckInProcessor struct {
  baseBoardingProcessor
}

func (l *luggageCheckInProcessor) ProcessFor(passenger *Passenger) {
  if !passenger.hasBoardingPass {
    fmt.Printf("旅客%s未辦理登機(jī)牌,不能托運(yùn)行李;\n", passenger.name)
    return
  }
  if passenger.hasLuggage {
    fmt.Printf("為旅客%s辦理行李托運(yùn);\n", passenger.name)
  }
  l.baseBoardingProcessor.ProcessFor(passenger)
}

// identityCheckProcessor 校驗(yàn)身份處理器
type identityCheckProcessor struct {
  baseBoardingProcessor
}

func (i *identityCheckProcessor) ProcessFor(passenger *Passenger) {
  if !passenger.hasBoardingPass {
    fmt.Printf("旅客%s未辦理登機(jī)牌,不能辦理身份校驗(yàn);\n", passenger.name)
    return
  }
  if !passenger.isPassIdentityCheck {
    fmt.Printf("為旅客%s核實(shí)身份信息;\n", passenger.name)
    passenger.isPassIdentityCheck = true
  }
  i.baseBoardingProcessor.ProcessFor(passenger)
}

// securityCheckProcessor 安檢處理器
type securityCheckProcessor struct {
  baseBoardingProcessor
}

func (s *securityCheckProcessor) ProcessFor(passenger *Passenger) {
  if !passenger.hasBoardingPass {
    fmt.Printf("旅客%s未辦理登機(jī)牌,不能進(jìn)行安檢;\n", passenger.name)
    return
  }
  if !passenger.isPassSecurityCheck {
    fmt.Printf("為旅客%s進(jìn)行安檢;\n", passenger.name)
    passenger.isPassSecurityCheck = true
  }
  s.baseBoardingProcessor.ProcessFor(passenger)
}

// completeBoardingProcessor 完成登機(jī)處理器
type completeBoardingProcessor struct {
  baseBoardingProcessor
}

func (c *completeBoardingProcessor) ProcessFor(passenger *Passenger) {
  if !passenger.hasBoardingPass ||
    !passenger.isPassIdentityCheck ||
    !passenger.isPassSecurityCheck {
    fmt.Printf("旅客%s登機(jī)檢查過程未完成,不能登機(jī);\n", passenger.name)
    return
  }
  passenger.isCompleteForBoarding = true
  fmt.Printf("旅客%s成功登機(jī);\n", passenger.name)
}

(四)測試程序

package chainofresponsibility

import "testing"

func TestChainOfResponsibility(t *testing.T) {
  boardingProcessor := BuildBoardingProcessorChain()
  passenger := &Passenger{
    name:                  "李四",
    hasBoardingPass:       false,
    hasLuggage:            true,
    isPassIdentityCheck:   false,
    isPassSecurityCheck:   false,
    isCompleteForBoarding: false,
  }
  boardingProcessor.ProcessFor(passenger)
}

// BuildBoardingProcessorChain 構(gòu)建登機(jī)流程處理鏈
func BuildBoardingProcessorChain() BoardingProcessor {
  completeBoardingNode := &completeBoardingProcessor{}

  securityCheckNode := &securityCheckProcessor{}
  securityCheckNode.SetNextProcessor(completeBoardingNode)

  identityCheckNode := &identityCheckProcessor{}
  identityCheckNode.SetNextProcessor(securityCheckNode)

  luggageCheckInNode := &luggageCheckInProcessor{}
  luggageCheckInNode.SetNextProcessor(identityCheckNode)

  boardingPassNode := &boardingPassProcessor{}
  boardingPassNode.SetNextProcessor(luggageCheckInNode)
  return boardingPassNode
}

(五)運(yùn)行結(jié)果

=== RUN   TestChainOfResponsibility
為旅客李四辦理登機(jī)牌;
為旅客李四辦理行李托運(yùn);
為旅客李四核實(shí)身份信息;
為旅客李四進(jìn)行安檢;
旅客李四成功登機(jī);
--- PASS: TestChainOfResponsibility (0.00s)
PASS
【轉(zhuǎn)存】Go語言設(shè)計(jì)模式

命令模式

(一)概念

命令模式是一種行為設(shè)計(jì)模式,它可將請求轉(zhuǎn)換為一個(gè)包含與請求相關(guān)的所有信息的獨(dú)立對象。該轉(zhuǎn)換讓你能根據(jù)不同的請求將方法參數(shù)化、延遲請求執(zhí)行或?qū)⑵浞湃腙?duì)列中,且能實(shí)現(xiàn)可撤銷操作。

方法參數(shù)化是指將每個(gè)請求參數(shù)傳入具體命令的工廠方法(go語言沒有構(gòu)造函數(shù))創(chuàng)建命令,同時(shí)具體命令會默認(rèn)設(shè)置好接受對象,這樣做的好處是不管請求參數(shù)個(gè)數(shù)及類型,還是接受對象有幾個(gè),都會被封裝到具體命令對象的成員字段上,并通過統(tǒng)一的Execute接口方法進(jìn)行調(diào)用,屏蔽各個(gè)請求的差異,便于命令擴(kuò)展,多命令組裝,回滾等;

(二)示例

控制電飯煲做飯是一個(gè)典型的命令模式的場景,電飯煲的控制面板會提供設(shè)置煮粥、蒸飯模式,及開始和停止按鈕,電飯煲控制系統(tǒng)會根據(jù)模式的不同設(shè)置相應(yīng)的火力,壓強(qiáng)及時(shí)間等參數(shù);煮粥,蒸飯就相當(dāng)于不同的命令,開始按鈕就相當(dāng)命令觸發(fā)器,設(shè)置好做飯模式,點(diǎn)擊開始按鈕電飯煲就開始運(yùn)行,同時(shí)還支持停止命令;

(三)電飯煲接收器

package command

import "fmt"

// ElectricCooker 電飯煲
type ElectricCooker struct {
  fire     string // 火力
  pressure string // 壓力
}

// SetFire 設(shè)置火力
func (e *ElectricCooker) SetFire(fire string) {
  e.fire = fire
}

// SetPressure 設(shè)置壓力
func (e *ElectricCooker) SetPressure(pressure string) {
  e.pressure = pressure
}

// Run 持續(xù)運(yùn)行指定時(shí)間
func (e *ElectricCooker) Run(duration string) string {
  return fmt.Sprintf("電飯煲設(shè)置火力為%s,壓力為%s,持續(xù)運(yùn)行%s;", e.fire, e.pressure, duration)
}

// Shutdown 停止
func (e *ElectricCooker) Shutdown() string {
  return "電飯煲停止運(yùn)行。"
}

(四)電飯煲命令

package command

// CookCommand 做飯指令接口
type CookCommand interface {
  Execute() string // 指令執(zhí)行方法
}

// steamRiceCommand 蒸飯指令
type steamRiceCommand struct {
  electricCooker *ElectricCooker // 電飯煲
}

func NewSteamRiceCommand(electricCooker *ElectricCooker) *steamRiceCommand {
  return &steamRiceCommand{
    electricCooker: electricCooker,
  }
}

func (s *steamRiceCommand) Execute() string {
  s.electricCooker.SetFire("中")
  s.electricCooker.SetPressure("正常")
  return "蒸飯:" + s.electricCooker.Run("30分鐘")
}

// cookCongeeCommand 煮粥指令
type cookCongeeCommand struct {
  electricCooker *ElectricCooker
}

func NewCookCongeeCommand(electricCooker *ElectricCooker) *cookCongeeCommand {
  return &cookCongeeCommand{
    electricCooker: electricCooker,
  }
}

func (c *cookCongeeCommand) Execute() string {
  c.electricCooker.SetFire("大")
  c.electricCooker.SetPressure("強(qiáng)")
  return "煮粥:" + c.electricCooker.Run("45分鐘")
}

// shutdownCommand 停止指令
type shutdownCommand struct {
  electricCooker *ElectricCooker
}

func NewShutdownCommand(electricCooker *ElectricCooker) *shutdownCommand {
  return &shutdownCommand{
    electricCooker: electricCooker,
  }
}

func (s *shutdownCommand) Execute() string {
  return s.electricCooker.Shutdown()
}

// ElectricCookerInvoker 電飯煲指令觸發(fā)器
type ElectricCookerInvoker struct {
  cookCommand CookCommand
}

// SetCookCommand 設(shè)置指令
func (e *ElectricCookerInvoker) SetCookCommand(cookCommand CookCommand) {
  e.cookCommand = cookCommand
}

// ExecuteCookCommand 執(zhí)行指令
func (e *ElectricCookerInvoker) ExecuteCookCommand() string {
  return e.cookCommand.Execute()
}

(五)測試程序

package command

import (
  "fmt"
  "testing"
)

func TestCommand(t *testing.T) {
  // 創(chuàng)建電飯煲,命令接受者
  electricCooker := new(ElectricCooker)
  // 創(chuàng)建電飯煲指令觸發(fā)器
  electricCookerInvoker := new(ElectricCookerInvoker)

  // 蒸飯
  steamRiceCommand := NewSteamRiceCommand(electricCooker)
  electricCookerInvoker.SetCookCommand(steamRiceCommand)
  fmt.Println(electricCookerInvoker.ExecuteCookCommand())

  // 煮粥
  cookCongeeCommand := NewCookCongeeCommand(electricCooker)
  electricCookerInvoker.SetCookCommand(cookCongeeCommand)
  fmt.Println(electricCookerInvoker.ExecuteCookCommand())

  // 停止
  shutdownCommand := NewShutdownCommand(electricCooker)
  electricCookerInvoker.SetCookCommand(shutdownCommand)
  fmt.Println(electricCookerInvoker.ExecuteCookCommand())
}

(六)運(yùn)行結(jié)果

=== RUN   TestCommand
蒸飯:電飯煲設(shè)置火力為中,壓力為正常,持續(xù)運(yùn)行30分鐘;
煮粥:電飯煲設(shè)置火力為大,壓力為強(qiáng),持續(xù)運(yùn)行45分鐘;
電飯煲停止運(yùn)行。
--- PASS: TestCommand (0.00s)
PASS
【轉(zhuǎn)存】Go語言設(shè)計(jì)模式

迭代器模式

(一)概念

迭代器模式是一種行為設(shè)計(jì)模式,讓你能在不暴露集合底層表現(xiàn)形式 (列表、 棧和樹等)的情況下遍歷集合中所有的元素。

在迭代器的幫助下, 客戶端可以用一個(gè)迭代器接口以相似的方式遍歷不同集合中的元素。

這里需要注意的是有兩個(gè)典型的迭代器接口需要分清楚;一個(gè)是集合類實(shí)現(xiàn)的可以創(chuàng)建迭代器的工廠方法接口一般命名為Iterable,包含的方法類似CreateIterator;另一個(gè)是迭代器本身的接口,命名為Iterator,有Next及hasMore兩個(gè)主要方法;

(二)示例

一個(gè)班級類中包括一個(gè)老師和若干個(gè)學(xué)生,我們要對班級所有成員進(jìn)行遍歷,班級中老師存儲在單獨(dú)的結(jié)構(gòu)字段中,學(xué)生存儲在另外一個(gè)slice字段中,通過迭代器,我們實(shí)現(xiàn)統(tǒng)一遍歷處理;

(三)班級成員

package iterator

import "fmt"

// Member 成員接口
type Member interface {
  Desc() string // 輸出成員描述信息
}

// Teacher 老師
type Teacher struct {
  name    string // 名稱
  subject string // 所教課程
}

// NewTeacher 根據(jù)姓名、課程創(chuàng)建老師對象
func NewTeacher(name, subject string) *Teacher {
  return &Teacher{
    name:    name,
    subject: subject,
  }
}

func (t *Teacher) Desc() string {
  return fmt.Sprintf("%s班主任老師負(fù)責(zé)教%s", t.name, t.subject)
}

// Student 學(xué)生
type Student struct {
  name     string // 姓名
  sumScore int    // 考試總分?jǐn)?shù)
}

// NewStudent 創(chuàng)建學(xué)生對象
func NewStudent(name string, sumScore int) *Student {
  return &Student{
    name:     name,
    sumScore: sumScore,
  }
}

func (t *Student) Desc() string {
  return fmt.Sprintf("%s同學(xué)考試總分為%d", t.name, t.sumScore)
}

(四)班級成員迭代器

package iterator

// Iterator 迭代器接口
type Iterator interface {
  Next() Member  // 迭代下一個(gè)成員
  HasMore() bool // 是否還有
}

// memberIterator 班級成員迭代器實(shí)現(xiàn)
type memberIterator struct {
  class *Class // 需迭代的班級
  index int    // 迭代索引
}

func (m *memberIterator) Next() Member {
  // 迭代索引為-1時(shí),返回老師成員,否則遍歷學(xué)生slice
  if m.index == -1 {
    m.index++
    return m.class.teacher
  }
  student := m.class.students[m.index]
  m.index++
  return student
}

func (m *memberIterator) HasMore() bool {
  return m.index < len(m.class.students)
}

// Iterable 可迭代集合接口,實(shí)現(xiàn)此接口返回迭代器
type Iterable interface {
  CreateIterator() Iterator
}

// Class 班級,包括老師和同學(xué)
type Class struct {
  name     string
  teacher  *Teacher
  students []*Student
}

// NewClass 根據(jù)班主任老師名稱,授課創(chuàng)建班級
func NewClass(name, teacherName, teacherSubject string) *Class {
  return &Class{
    name:    name,
    teacher: NewTeacher(teacherName, teacherSubject),
  }
}

// CreateIterator 創(chuàng)建班級迭代器
func (c *Class) CreateIterator() Iterator {
  return &memberIterator{
    class: c,
    index: -1, // 迭代索引初始化為-1,從老師開始迭代
  }
}

func (c *Class) Name() string {
  return c.name
}

// AddStudent 班級添加同學(xué)
func (c *Class) AddStudent(students ...*Student) {
  c.students = append(c.students, students...)
}

(五)測試程序

package iterator

import (
  "fmt"
  "testing"
)

func TestIterator(t *testing.T) {
  class := NewClass("三年級一班", "王明", "數(shù)學(xué)課")
  class.AddStudent(NewStudent("張三", 389),
    NewStudent("李四", 378),
    NewStudent("王五", 347))

  fmt.Printf("%s成員如下:\n", class.Name())
  classIterator := class.CreateIterator()
  for classIterator.HasMore() {
    member := classIterator.Next()
    fmt.Println(member.Desc())
  }
}

(六)運(yùn)行結(jié)果

=== RUN   TestIterator
三年級一班成員如下:
王明班主任老師負(fù)責(zé)教數(shù)學(xué)課
張三同學(xué)考試總分為389
李四同學(xué)考試總分為378
王五同學(xué)考試總分為347
--- PASS: TestIterator (0.00s)
PASS
【轉(zhuǎn)存】Go語言設(shè)計(jì)模式

中介者模式

(一)概念

中介者模式是一種行為設(shè)計(jì)模式,能讓你減少對象之間混亂無序的依賴關(guān)系。該模式會限制對象之間的直接交互,迫使它們通過一個(gè)中介者對象進(jìn)行合作,將網(wǎng)狀依賴變?yōu)樾菭钜蕾嚒?/p>

中介者能使得程序更易于修改和擴(kuò)展,而且能更方便地對獨(dú)立的組件進(jìn)行復(fù)用,因?yàn)樗鼈儾辉僖蕾囉诤芏嗥渌念悺?/p>

中介者模式與觀察者模式之間的區(qū)別是,中介者模式解決的是同類或者不同類的多個(gè)對象之間多對多的依賴關(guān)系,觀察者模式解決的是多個(gè)對象與一個(gè)對象之間的多對一的依賴關(guān)系。

(二)示例

機(jī)場塔臺調(diào)度系統(tǒng)是一個(gè)體現(xiàn)中介者模式的典型示例,假設(shè)是一個(gè)小機(jī)場,每次只能同時(shí)允許一架飛機(jī)起降,每架靠近機(jī)場的飛機(jī)需要先與塔臺溝通是否可以降落,如果沒有空閑的跑道,需要在天空盤旋等待,如果有飛機(jī)離港,等待的飛機(jī)會收到塔臺的通知,按先后順序降落;這種方式,免去多架飛機(jī)同時(shí)到達(dá)機(jī)場需要相互溝通降落順序的復(fù)雜性,減少多個(gè)飛機(jī)間的依賴關(guān)系,簡化業(yè)務(wù)邏輯,從而降低系統(tǒng)出問題的風(fēng)險(xiǎn)。

(三)飛機(jī)對象

package mediator

import "fmt"

// Aircraft 飛機(jī)接口
type Aircraft interface {
  ApproachAirport() // 抵達(dá)機(jī)場空域
  DepartAirport()   // 飛離機(jī)場
}

// airliner 客機(jī)
type airliner struct {
  name            string          // 客機(jī)型號
  airportMediator AirportMediator // 機(jī)場調(diào)度
}

// NewAirliner 根據(jù)指定型號及機(jī)場調(diào)度創(chuàng)建客機(jī)
func NewAirliner(name string, mediator AirportMediator) *airliner {
  return &airliner{
    name:            name,
    airportMediator: mediator,
  }
}

func (a *airliner) ApproachAirport() {
  if !a.airportMediator.CanLandAirport(a) { // 請求塔臺是否可以降落
    fmt.Printf("機(jī)場繁忙,客機(jī)%s繼續(xù)等待降落;\n", a.name)
    return
  }
  fmt.Printf("客機(jī)%s成功滑翔降落機(jī)場;\n", a.name)
}

func (a *airliner) DepartAirport() {
  fmt.Printf("客機(jī)%s成功滑翔起飛,離開機(jī)場;\n", a.name)
  a.airportMediator.NotifyWaitingAircraft() // 通知等待的其他飛機(jī)
}

// helicopter 直升機(jī)
type helicopter struct {
  name            string
  airportMediator AirportMediator
}

// NewHelicopter 根據(jù)指定型號及機(jī)場調(diào)度創(chuàng)建直升機(jī)
func NewHelicopter(name string, mediator AirportMediator) *helicopter {
  return &helicopter{
    name:            name,
    airportMediator: mediator,
  }
}

func (h *helicopter) ApproachAirport() {
  if !h.airportMediator.CanLandAirport(h) { // 請求塔臺是否可以降落
    fmt.Printf("機(jī)場繁忙,直升機(jī)%s繼續(xù)等待降落;\n", h.name)
    return
  }
  fmt.Printf("直升機(jī)%s成功垂直降落機(jī)場;\n", h.name)
}

func (h *helicopter) DepartAirport() {
  fmt.Printf("直升機(jī)%s成功垂直起飛,離開機(jī)場;\n", h.name)
  h.airportMediator.NotifyWaitingAircraft() // 通知其他等待降落的飛機(jī)
}

(四)機(jī)場塔臺

package mediator

// AirportMediator 機(jī)場調(diào)度中介者
type AirportMediator interface {
  CanLandAirport(aircraft Aircraft) bool // 確認(rèn)是否可以降落
  NotifyWaitingAircraft()                // 通知等待降落的其他飛機(jī)
}

// ApproachTower 機(jī)場塔臺
type ApproachTower struct {
  hasFreeAirstrip bool
  waitingQueue    []Aircraft // 等待降落的飛機(jī)隊(duì)列
}

func (a *ApproachTower) CanLandAirport(aircraft Aircraft) bool {
  if a.hasFreeAirstrip {
    a.hasFreeAirstrip = false
    return true
  }
  // 沒有空余的跑道,加入等待隊(duì)列
  a.waitingQueue = append(a.waitingQueue, aircraft)
  return false
}

func (a *ApproachTower) NotifyWaitingAircraft() {
  if !a.hasFreeAirstrip {
    a.hasFreeAirstrip = true
  }
  if len(a.waitingQueue) > 0 {
    // 如果存在等待降落的飛機(jī),通知第一個(gè)降落
    first := a.waitingQueue[0]
    a.waitingQueue = a.waitingQueue[1:]
    first.ApproachAirport()
  }
}

(五)測試程序

package mediator

import "testing"

func TestMediator(t *testing.T) {
  // 創(chuàng)建機(jī)場調(diào)度塔臺
  airportMediator := &ApproachTower{hasFreeAirstrip: true}
  // 創(chuàng)建C919客機(jī)
  c919Airliner := NewAirliner("C919", airportMediator)
  // 創(chuàng)建米-26重型運(yùn)輸直升機(jī)
  m26Helicopter := NewHelicopter("米-26", airportMediator)

  c919Airliner.ApproachAirport()  // c919進(jìn)港降落
  m26Helicopter.ApproachAirport() // 米-26進(jìn)港等待

  c919Airliner.DepartAirport()  // c919飛離,等待的米-26進(jìn)港降落
  m26Helicopter.DepartAirport() // 最后米-26飛離
}

(六)運(yùn)行結(jié)果

=== RUN   TestMediator
客機(jī)C919成功滑翔降落機(jī)場;
機(jī)場繁忙,直升機(jī)米-26繼續(xù)等待降落;
客機(jī)C919成功滑翔起飛,離開機(jī)場;
直升機(jī)米-26成功垂直降落機(jī)場;
直升機(jī)米-26成功垂直起飛,離開機(jī)場;
--- PASS: TestMediator (0.00s)
PASS
【轉(zhuǎn)存】Go語言設(shè)計(jì)模式

備忘錄模式

(一)概念

備忘錄模式是一種行為設(shè)計(jì)模式, 允許在不暴露對象實(shí)現(xiàn)細(xì)節(jié)的情況下保存和恢復(fù)對象之前的狀態(tài)。

備忘錄不會影響它所處理的對象的內(nèi)部結(jié)構(gòu), 也不會影響快照中保存的數(shù)據(jù)。

一般情況由原發(fā)對象保存生成的備忘錄對象的狀態(tài)不能被除原發(fā)對象之外的對象訪問,所以通過內(nèi)部類定義具體的備忘錄對象是比較安全的,但是go語言不支持內(nèi)部類定義的方式,因此go語言實(shí)現(xiàn)備忘錄對象時(shí),首先將備忘錄保存的狀態(tài)設(shè)為非導(dǎo)出字段,避免外部對象訪問,其次將原發(fā)對象的引用保存到備忘錄對象中,當(dāng)通過備忘錄對象恢復(fù)時(shí),直接操作備忘錄的恢復(fù)方法,將備份數(shù)據(jù)狀態(tài)設(shè)置到原發(fā)對象中,完成恢復(fù)。

(二)示例

大家平時(shí)玩的角色扮演闖關(guān)游戲的存檔機(jī)制就可以通過備忘錄模式實(shí)現(xiàn),每到一個(gè)關(guān)鍵關(guān)卡,玩家經(jīng)常會先保存游戲存檔,用于闖關(guān)失敗后重置,存檔會把角色狀態(tài)及場景狀態(tài)保存到備忘錄中,同時(shí)將需要恢復(fù)游戲的引用存入備忘錄,用于關(guān)卡重置;

(三)闖關(guān)游戲

package memento

import "fmt"

// Originator 備忘錄模式原發(fā)器接口
type Originator interface {
  Save(tag string) Memento // 當(dāng)前狀態(tài)保存?zhèn)渫?}

// RolesPlayGame 支持存檔的RPG游戲
type RolesPlayGame struct {
  name          string   // 游戲名稱
  rolesState    []string // 游戲角色狀態(tài)
  scenarioState string   // 游戲場景狀態(tài)
}

// NewRolesPlayGame 根據(jù)游戲名稱和角色名,創(chuàng)建RPG游戲
func NewRolesPlayGame(name string, roleName string) *RolesPlayGame {
  return &RolesPlayGame{
    name:          name,
    rolesState:    []string{roleName, "血量100"}, // 默認(rèn)滿血
    scenarioState: "開始通過第一關(guān)",                   // 默認(rèn)第一關(guān)開始
  }
}

// Save 保存RPG游戲角色狀態(tài)及場景狀態(tài)到指定標(biāo)簽歸檔
func (r *RolesPlayGame) Save(tag string) Memento {
  return newRPGArchive(tag, r.rolesState, r.scenarioState, r)
}

func (r *RolesPlayGame) SetRolesState(rolesState []string) {
  r.rolesState = rolesState
}

func (r *RolesPlayGame) SetScenarioState(scenarioState string) {
  r.scenarioState = scenarioState
}

// String 輸出RPG游戲簡要信息
func (r *RolesPlayGame) String() string {
  return fmt.Sprintf("在%s游戲中,玩家使用%s,%s,%s;", r.name, r.rolesState[0], r.rolesState[1], r.scenarioState)
}

(四)游戲存檔

package memento

import "fmt"

// Memento 備忘錄接口
type Memento interface {
  Tag() string // 備忘錄標(biāo)簽
  Restore()    // 根據(jù)備忘錄存儲數(shù)據(jù)狀態(tài)恢復(fù)原對象
}

// rpgArchive rpg游戲存檔,
type rpgArchive struct {
  tag           string         // 存檔標(biāo)簽
  rolesState    []string       // 存檔的角色狀態(tài)
  scenarioState string         // 存檔游戲場景狀態(tài)
  rpg           *RolesPlayGame // rpg游戲引用
}

// newRPGArchive 根據(jù)標(biāo)簽,角色狀態(tài),場景狀態(tài),rpg游戲引用,創(chuàng)建游戲歸檔備忘錄
func newRPGArchive(tag string, rolesState []string, scenarioState string, rpg *RolesPlayGame) *rpgArchive {
  return &rpgArchive{
    tag:           tag,
    rolesState:    rolesState,
    scenarioState: scenarioState,
    rpg:           rpg,
  }
}

func (r *rpgArchive) Tag() string {
  return r.tag
}

// Restore 根據(jù)歸檔數(shù)據(jù)恢復(fù)游戲狀態(tài)
func (r *rpgArchive) Restore() {
  r.rpg.SetRolesState(r.rolesState)
  r.rpg.SetScenarioState(r.scenarioState)
}

// RPGArchiveManager RPG游戲歸檔管理器
type RPGArchiveManager struct {
  archives map[string]Memento // 存儲歸檔標(biāo)簽對應(yīng)歸檔
}

func NewRPGArchiveManager() *RPGArchiveManager {
  return &RPGArchiveManager{
    archives: make(map[string]Memento),
  }
}

// Reload 根據(jù)標(biāo)簽重新加載歸檔數(shù)據(jù)
func (r *RPGArchiveManager) Reload(tag string) {
  if archive, ok := r.archives[tag]; ok {
    fmt.Printf("重新加載%s;\n", tag)
    archive.Restore()
  }
}

// Put 保存歸檔數(shù)據(jù)
func (r *RPGArchiveManager) Put(memento Memento) {
  r.archives[memento.Tag()] = memento
}

(五)測試程序

package memento

import (
  "fmt"
  "testing"
)

func TestMemento(t *testing.T) {
  // 創(chuàng)建RPG游戲存檔管理器
  rpgManager := NewRPGArchiveManager()
  // 創(chuàng)建RPG游戲
  rpg := NewRolesPlayGame("暗黑破壞神2", "野蠻人戰(zhàn)士")
  fmt.Println(rpg)                  // 輸出游戲當(dāng)前狀態(tài)
  rpgManager.Put(rpg.Save("第一關(guān)存檔")) // 游戲存檔

  // 第一關(guān)闖關(guān)失敗
  rpg.SetRolesState([]string{"野蠻人戰(zhàn)士", "死亡"})
  rpg.SetScenarioState("第一關(guān)闖關(guān)失敗")
  fmt.Println(rpg)

  // 恢復(fù)存檔,重新闖關(guān)
  rpgManager.Reload("第一關(guān)存檔")
  fmt.Println(rpg)
}

(六)運(yùn)行結(jié)果

=== RUN   TestMemento
在暗黑破壞神2游戲中,玩家使用野蠻人戰(zhàn)士,血量100,開始通過第一關(guān);
在暗黑破壞神2游戲中,玩家使用野蠻人戰(zhàn)士,死亡,第一關(guān)闖關(guān)失敗;
重新加載第一關(guān)存檔;
在暗黑破壞神2游戲中,玩家使用野蠻人戰(zhàn)士,血量100,開始通過第一關(guān);
--- PASS: TestMemento (0.00s)
PASS
【轉(zhuǎn)存】Go語言設(shè)計(jì)模式

觀察者模式

(一)概念

觀察者模式是一種行為設(shè)計(jì)模式,允許你定義一種訂閱機(jī)制,可在對象事件發(fā)生時(shí)通知多個(gè) “觀察” 該對象的其他對象。

觀察者模式提供了一種作用于任何實(shí)現(xiàn)了訂閱者接口的對象的機(jī)制,可對其事件進(jìn)行訂閱和取消訂閱。

觀察者模式是最常用的模式之一,是事件總線,分布式消息中間件等各種事件機(jī)制的原始理論基礎(chǔ),常用于解耦多對一的對象依賴關(guān)系;

增強(qiáng)的實(shí)現(xiàn)功能包括:

  • 當(dāng)被觀察者通過異步實(shí)現(xiàn)通知多個(gè)觀察者時(shí)就相當(dāng)于單進(jìn)程實(shí)例的消息總線;
  • 同時(shí)還可以根據(jù)業(yè)務(wù)需要,將被觀察者所有數(shù)據(jù)狀態(tài)變更進(jìn)行分類為不同的主題,觀察者通過不同主題進(jìn)行訂閱;
  • 同一個(gè)主題又可分為增加,刪除,修改事件行為;
  • 每個(gè)主題可以實(shí)現(xiàn)一個(gè)線程池,多個(gè)主題通過不同的線程池進(jìn)行處理隔離,線程池可以設(shè)置并發(fā)線程大小、緩沖區(qū)大小及調(diào)度策略,比如先進(jìn)先出,優(yōu)先級等策略;
  • 觀察者處理事件時(shí)有可能出現(xiàn)異常,所以也可以注冊異常處理函數(shù),異常處理也可以通過異常類型進(jìn)行分類;
  • 根據(jù)業(yè)務(wù)需求也可以實(shí)現(xiàn)通知異常重試,延遲通知等功能;

(二)示例

信用卡業(yè)務(wù)消息提醒可通過觀察者模式實(shí)現(xiàn),業(yè)務(wù)消息包括日常消費(fèi),出賬單,賬單逾期,消息提醒包括短信、郵件及電話,根據(jù)不同業(yè)務(wù)的場景會采用不同的消息提醒方式或者多種消息提醒方式,這里信用卡相當(dāng)于被觀察者,觀察者相當(dāng)于不同的通知方式;日常消費(fèi)通過短信通知,出賬單通過郵件通知,賬單逾期三種方式都會進(jìn)行通知;

(三)通知方式

package observer

import "fmt"

// Subscriber 訂閱者接口
type Subscriber interface {
  Name() string          //訂閱者名稱
  Update(message string) //訂閱更新方法
}

// shortMessage 信用卡消息短信訂閱者
type shortMessage struct{}

func (s *shortMessage) Name() string {
  return "手機(jī)短息"
}

func (s *shortMessage) Update(message string) {
  fmt.Printf("通過【%s】發(fā)送消息:%s\n", s.Name(), message)
}

// email 信用卡消息郵箱訂閱者
type email struct{}

func (e *email) Name() string {
  return "電子郵件"
}

func (e *email) Update(message string) {
  fmt.Printf("通過【%s】發(fā)送消息:%s\n", e.Name(), message)
}

// telephone 信用卡消息電話訂閱者
type telephone struct{}

func (t *telephone) Name() string {
  return "電話"
}

func (t *telephone) Update(message string) {
  fmt.Printf("通過【%s】告知:%s\n", t.Name(), message)
}

(四)信用卡業(yè)務(wù)

package observer

import "fmt"

// MsgType 信用卡消息類型
type MsgType int

const (
  ConsumeType MsgType = iota // 消費(fèi)消息類型
  BillType                   // 賬單消息類型
  ExpireType                 // 逾期消息類型
)

// CreditCard 信用卡
type CreditCard struct {
  holder          string                   // 持卡人
  consumeSum      float32                  // 消費(fèi)總金額
  subscriberGroup map[MsgType][]Subscriber // 根據(jù)消息類型分組訂閱者
}

// NewCreditCard 指定持卡人創(chuàng)建信用卡
func NewCreditCard(holder string) *CreditCard {
  return &CreditCard{
    holder:          holder,
    subscriberGroup: make(map[MsgType][]Subscriber),
  }
}

// Subscribe 支持訂閱多種消息類型
func (c *CreditCard) Subscribe(subscriber Subscriber, msgTypes ...MsgType) {
  for _, msgType := range msgTypes {
    c.subscriberGroup[msgType] = append(c.subscriberGroup[msgType], subscriber)
  }
}

// Unsubscribe 解除訂閱多種消息類型
func (c *CreditCard) Unsubscribe(subscriber Subscriber, msgTypes ...MsgType) {
  for _, msgType := range msgTypes {
    if subs, ok := c.subscriberGroup[msgType]; ok {
      c.subscriberGroup[msgType] = removeSubscriber(subs, subscriber)
    }
  }
}

func removeSubscriber(subscribers []Subscriber, toRemove Subscriber) []Subscriber {
  length := len(subscribers)
  for i, subscriber := range subscribers {
    if toRemove.Name() == subscriber.Name() {
      subscribers[length-1], subscribers[i] = subscribers[i], subscribers[length-1]
      return subscribers[:length-1]
    }
  }
  return subscribers
}

// Consume 信用卡消費(fèi)
func (c *CreditCard) Consume(money float32) {
  c.consumeSum += money
  c.notify(ConsumeType, fmt.Sprintf("尊敬的持卡人%s,您當(dāng)前消費(fèi)%.2f元;", c.holder, money))
}

// SendBill 發(fā)送信用卡賬單
func (c *CreditCard) SendBill() {
  c.notify(BillType, fmt.Sprintf("尊敬的持卡人%s,您本月賬單已出,消費(fèi)總額%.2f元;", c.holder, c.consumeSum))
}

// Expire 逾期通知
func (c *CreditCard) Expire() {
  c.notify(ExpireType, fmt.Sprintf("尊敬的持卡人%s,您本月賬單已逾期,請及時(shí)還款,總額%.2f元;", c.holder, c.consumeSum))
}

// notify 根據(jù)消息類型通知訂閱者
func (c *CreditCard) notify(msgType MsgType, message string) {
  if subs, ok := c.subscriberGroup[msgType]; ok {
    for _, sub := range subs {
      sub.Update(message)
    }
  }
}

(五)測試程序

package observer

import "testing"

func TestObserver(t *testing.T) {
  // 創(chuàng)建張三的信用卡
  creditCard := NewCreditCard("張三")
  // 短信通知訂閱信用卡消費(fèi)及逾期消息
  creditCard.Subscribe(new(shortMessage), ConsumeType, ExpireType)
  // 電子郵件通知訂閱信用卡賬單及逾期消息
  creditCard.Subscribe(new(email), BillType, ExpireType)
  // 電話通知訂閱信用卡逾期消息,同時(shí)逾期消息通過三種方式通知
  creditCard.Subscribe(new(telephone), ExpireType)

  creditCard.Consume(500.00) // 信用卡消費(fèi)
  creditCard.Consume(800.00) // 信用卡消費(fèi)
  creditCard.SendBill()      // 信用卡發(fā)送賬單
  creditCard.Expire()        // 信用卡逾期

  // 信用卡逾期消息取消電子郵件及短信通知訂閱
  creditCard.Unsubscribe(new(email), ExpireType)
  creditCard.Unsubscribe(new(shortMessage), ExpireType)
  creditCard.Consume(300.00) // 信用卡消費(fèi)
  creditCard.Expire()        // 信用卡逾期
}

(六)運(yùn)行結(jié)果

=== RUN   TestObserver
通過【手機(jī)短息】發(fā)送消息:尊敬的持卡人張三,您當(dāng)前消費(fèi)500.00元;
通過【手機(jī)短息】發(fā)送消息:尊敬的持卡人張三,您當(dāng)前消費(fèi)800.00元;
通過【電子郵件】發(fā)送消息:尊敬的持卡人張三,您本月賬單已出,消費(fèi)總額1300.00元;
通過【手機(jī)短息】發(fā)送消息:尊敬的持卡人張三,您本月賬單已逾期,請及時(shí)還款,總額1300.00元;
通過【電子郵件】發(fā)送消息:尊敬的持卡人張三,您本月賬單已逾期,請及時(shí)還款,總額1300.00元;
通過【電話】告知:尊敬的持卡人張三,您本月賬單已逾期,請及時(shí)還款,總額1300.00元;
通過【手機(jī)短息】發(fā)送消息:尊敬的持卡人張三,您當(dāng)前消費(fèi)300.00元;
通過【電話】告知:尊敬的持卡人張三,您本月賬單已逾期,請及時(shí)還款,總額1600.00元;
--- PASS: TestObserver (0.00s)
PASS
【轉(zhuǎn)存】Go語言設(shè)計(jì)模式

狀態(tài)模式

(一)概念

狀態(tài)模式是一種行為設(shè)計(jì)模式,讓你能在一個(gè)對象的內(nèi)部狀態(tài)變化時(shí)改變其行為,使其看上去就像改變了自身所屬的類一樣。

該模式將與狀態(tài)相關(guān)的行為抽取到獨(dú)立的狀態(tài)類中,讓原對象將工作委派給這些類的實(shí)例,而不是自行進(jìn)行處理。

狀態(tài)遷移有四個(gè)元素組成,起始狀態(tài)、觸發(fā)遷移的事件,終止?fàn)顟B(tài)以及要執(zhí)行的動作,每個(gè)具體的狀態(tài)包含觸發(fā)狀態(tài)遷移的執(zhí)行方法,遷移方法的實(shí)現(xiàn)是執(zhí)行持有狀態(tài)對象的動作方法,同時(shí)設(shè)置狀態(tài)為下一個(gè)流轉(zhuǎn)狀態(tài);持有狀態(tài)的業(yè)務(wù)對象包含有觸發(fā)狀態(tài)遷移方法,這些遷移方法將請求委托給當(dāng)前具體狀態(tài)對象的遷移方法。

(二)示例

IPhone手機(jī)充電就是一個(gè)手機(jī)電池狀態(tài)的流轉(zhuǎn),一開始手機(jī)處于有電狀態(tài),插入充電插頭后,繼續(xù)充電到滿電狀態(tài),并進(jìn)入斷電保護(hù),拔出充電插頭后使用手機(jī),由滿電逐漸變?yōu)闆]電,最終關(guān)機(jī);

狀態(tài)遷移表:

起始狀態(tài) 觸發(fā)事件 終止?fàn)顟B(tài) 執(zhí)行動作
有電 插入充電線 滿電 充電
有電 拔出充電線 沒電 耗電
滿電 插入充電線 滿電 停止充電
滿電 拔出充電線 有電 耗電
沒電 插入充電線 有電 充電
沒電 拔出充電線 沒電 關(guān)機(jī)

(三)電池狀態(tài)

package state

import "fmt"

// BatteryState 電池狀態(tài)接口,支持手機(jī)充電線插拔事件
type BatteryState interface {
  ConnectPlug(iPhone *IPhone) string
  DisconnectPlug(iPhone *IPhone) string
}

// fullBatteryState 滿電狀態(tài)
type fullBatteryState struct{}

func (s *fullBatteryState) String() string {
  return "滿電狀態(tài)"
}

func (s *fullBatteryState) ConnectPlug(iPhone *IPhone) string {
  return iPhone.pauseCharge()
}

func (s *fullBatteryState) DisconnectPlug(iPhone *IPhone) string {
  iPhone.SetBatteryState(PartBatteryState)
  return fmt.Sprintf("%s,%s轉(zhuǎn)為%s", iPhone.consume(), s, PartBatteryState)
}

// emptyBatteryState 空電狀態(tài)
type emptyBatteryState struct{}

func (s *emptyBatteryState) String() string {
  return "沒電狀態(tài)"
}

func (s *emptyBatteryState) ConnectPlug(iPhone *IPhone) string {
  iPhone.SetBatteryState(PartBatteryState)
  return fmt.Sprintf("%s,%s轉(zhuǎn)為%s", iPhone.charge(), s, PartBatteryState)
}

func (s *emptyBatteryState) DisconnectPlug(iPhone *IPhone) string {
  return iPhone.shutdown()
}

// partBatteryState 部分電狀態(tài)
type partBatteryState struct{}

func (s *partBatteryState) String() string {
  return "有電狀態(tài)"
}

func (s *partBatteryState) ConnectPlug(iPhone *IPhone) string {
  iPhone.SetBatteryState(FullBatteryState)
  return fmt.Sprintf("%s,%s轉(zhuǎn)為%s", iPhone.charge(), s, FullBatteryState)
}

func (s *partBatteryState) DisconnectPlug(iPhone *IPhone) string {
  iPhone.SetBatteryState(EmptyBatteryState)
  return fmt.Sprintf("%s,%s轉(zhuǎn)為%s", iPhone.consume(), s, EmptyBatteryState)
}

(四)IPhone手機(jī)

package state

import "fmt"

// 電池狀態(tài)單例,全局統(tǒng)一使用三個(gè)狀態(tài)的單例,不需要重復(fù)創(chuàng)建
var (
  FullBatteryState  = new(fullBatteryState)  // 滿電
  EmptyBatteryState = new(emptyBatteryState) // 空電
  PartBatteryState  = new(partBatteryState)  // 部分電
)

// IPhone 已手機(jī)充電為例,實(shí)現(xiàn)狀態(tài)模式
type IPhone struct {
  model        string       // 手機(jī)型號
  batteryState BatteryState // 電池狀態(tài)
}

// NewIPhone 創(chuàng)建指定型號手機(jī)
func NewIPhone(model string) *IPhone {
  return &IPhone{
    model:        model,
    batteryState: PartBatteryState,
  }
}

// BatteryState 輸出電池當(dāng)前狀態(tài)
func (i *IPhone) BatteryState() string {
  return fmt.Sprintf("iPhone %s 當(dāng)前為%s", i.model, i.batteryState)
}

// ConnectPlug 連接充電線
func (i *IPhone) ConnectPlug() string {
  return fmt.Sprintf("iPhone %s 連接電源線,%s", i.model, i.batteryState.ConnectPlug(i))
}

// DisconnectPlug 斷開充電線
func (i *IPhone) DisconnectPlug() string {
  return fmt.Sprintf("iPhone %s 斷開電源線,%s", i.model, i.batteryState.DisconnectPlug(i))
}

// SetBatteryState 設(shè)置電池狀態(tài)
func (i *IPhone) SetBatteryState(state BatteryState) {
  i.batteryState = state
}

func (i *IPhone) charge() string {
  return "正在充電"
}

func (i *IPhone) pauseCharge() string {
  return "電已滿,暫停充電"
}

func (i *IPhone) shutdown() string {
  return "手機(jī)關(guān)閉"
}

func (i *IPhone) consume() string {
  return "使用中,消耗電量"
}

(五)測試程序

package state

import (
  "fmt"
  "testing"
)

func TestState(t *testing.T) {
  iPhone13Pro := NewIPhone("13 pro") // 剛創(chuàng)建的手機(jī)有部分電

  fmt.Println(iPhone13Pro.BatteryState()) // 打印部分電狀態(tài)
  fmt.Println(iPhone13Pro.ConnectPlug())  // 插上電源插頭,繼續(xù)充滿電
  fmt.Println(iPhone13Pro.ConnectPlug())  // 滿電后再充電,會觸發(fā)滿電保護(hù)

  fmt.Println(iPhone13Pro.DisconnectPlug()) // 拔掉電源,使用手機(jī)消耗電量,變?yōu)橛胁糠蛛?  fmt.Println(iPhone13Pro.DisconnectPlug()) // 一直使用手機(jī),直到?jīng)]電
  fmt.Println(iPhone13Pro.DisconnectPlug()) // 沒電后會關(guān)機(jī)

  fmt.Println(iPhone13Pro.ConnectPlug()) // 再次插上電源一會,變?yōu)橛须姞顟B(tài)
}

(六)運(yùn)行結(jié)果

=== RUN   TestState
iPhone 13 pro 當(dāng)前為有電狀態(tài)
iPhone 13 pro 連接電源線,正在充電,有電狀態(tài)轉(zhuǎn)為滿電狀態(tài)
iPhone 13 pro 連接電源線,電已滿,暫停充電
iPhone 13 pro 斷開電源線,使用中,消耗電量,滿電狀態(tài)轉(zhuǎn)為有電狀態(tài)
iPhone 13 pro 斷開電源線,使用中,消耗電量,有電狀態(tài)轉(zhuǎn)為沒電狀態(tài)
iPhone 13 pro 斷開電源線,手機(jī)關(guān)閉
iPhone 13 pro 連接電源線,正在充電,沒電狀態(tài)轉(zhuǎn)為有電狀態(tài)
--- PASS: TestState (0.00s)
PASS
【轉(zhuǎn)存】Go語言設(shè)計(jì)模式

策略模式

(一)概念

策略模式是一種行為設(shè)計(jì)模式,它能讓你定義一系列算法,并將每種算法分別放入獨(dú)立的類中,以使算法的對象能夠相互替換。

原始對象被稱為上下文,它包含指向策略對象的引用并將執(zhí)行行為的任務(wù)分派給策略對象。為了改變上下文完成其工作的方式,其他對象可以使用另一個(gè)對象來替換當(dāng)前鏈接的策略對象。

策略模式是最常用的設(shè)計(jì)模式,也是比較簡單的設(shè)計(jì)模式,是以多態(tài)替換條件表達(dá)式重構(gòu)方法的具體實(shí)現(xiàn),是面向接口編程原則的最直接體現(xiàn);

(二)示例

北京是一個(gè)四季分明的城市,每個(gè)季節(jié)天氣情況都有明顯特點(diǎn);我們定義一個(gè)顯示天氣情況的季節(jié)接口,具體的四季實(shí)現(xiàn),都會保存一個(gè)城市和天氣情況的映射表,城市對象會包含季節(jié)接口,隨著四季的變化,天氣情況也隨之變化;

(三)四季天氣

package strategy

import "fmt"

// Season 季節(jié)的策略接口,不同季節(jié)表現(xiàn)得天氣不同
type Season interface {
  ShowWeather(city string) string // 顯示指定城市的天氣情況
}

type spring struct {
  weathers map[string]string // 存儲不同城市春天氣候
}

func NewSpring() *spring {
  return &spring{
    weathers: map[string]string{"北京": "干燥多風(fēng)", "昆明": "清涼舒適"},
  }
}

func (s *spring) ShowWeather(city string) string {
  return fmt.Sprintf("%s的春天,%s;", city, s.weathers[city])
}

type summer struct {
  weathers map[string]string // 存儲不同城市夏天氣候
}

func NewSummer() *summer {
  return &summer{
    weathers: map[string]string{"北京": "高溫多雨", "昆明": "清涼舒適"},
  }
}

func (s *summer) ShowWeather(city string) string {
  return fmt.Sprintf("%s的夏天,%s;", city, s.weathers[city])
}

type autumn struct {
  weathers map[string]string // 存儲不同城市秋天氣候
}

func NewAutumn() *autumn {
  return &autumn{
    weathers: map[string]string{"北京": "涼爽舒適", "昆明": "清涼舒適"},
  }
}

func (a *autumn) ShowWeather(city string) string {
  return fmt.Sprintf("%s的秋天,%s;", city, a.weathers[city])
}

type winter struct {
  weathers map[string]string // 存儲不同城市冬天氣候
}

func NewWinter() *winter {
  return &winter{
    weathers: map[string]string{"北京": "干燥寒冷", "昆明": "清涼舒適"},
  }
}

func (w *winter) ShowWeather(city string) string {
  return fmt.Sprintf("%s的冬天,%s;", city, w.weathers[city])
}

(四)城市氣候

package strategy

import (
  "fmt"
)

// City 城市
type City struct {
  name    string
  feature string
  season  Season
}

// NewCity 根據(jù)名稱及季候特征創(chuàng)建城市
func NewCity(name, feature string) *City {
  return &City{
    name:    name,
    feature: feature,
  }
}

// SetSeason 設(shè)置不同季節(jié),類似天氣在不同季節(jié)的不同策略
func (c *City) SetSeason(season Season) {
  c.season = season
}

// String 顯示城市的氣候信息
func (c *City) String() string {
  return fmt.Sprintf("%s%s,%s", c.name, c.feature, c.season.ShowWeather(c.name))
}

(五)測試程序

package strategy

import (
  "fmt"
  "testing"
)

func TestStrategy(t *testing.T) {
  Beijing := NewCity("北京", "四季分明")

  Beijing.SetSeason(NewSpring())
  fmt.Println(Beijing)

  Beijing.SetSeason(NewSummer())
  fmt.Println(Beijing)

  Beijing.SetSeason(NewAutumn())
  fmt.Println(Beijing)

  Beijing.SetSeason(NewWinter())
  fmt.Println(Beijing)
}

(六)運(yùn)行結(jié)果

=== RUN   TestStrategy
北京四季分明,北京的春天,干燥多風(fēng);
北京四季分明,北京的夏天,高溫多雨;
北京四季分明,北京的秋天,涼爽舒適;
北京四季分明,北京的冬天,干燥寒冷;
--- PASS: TestStrategy (0.00s)
PASS
【轉(zhuǎn)存】Go語言設(shè)計(jì)模式

模板方法模式

(一)概念

模板方法模式是一種行為設(shè)計(jì)模式,它在超類中定義了一個(gè)算法的框架,允許子類在不修改結(jié)構(gòu)的情況下重寫算法的特定步驟。

由于GO語言沒有繼承的語法,模板方法又是依賴?yán)^承實(shí)現(xiàn)的設(shè)計(jì)模式,因此GO語言實(shí)現(xiàn)模板方法比較困難, GO語言支持隱式內(nèi)嵌字段“繼承”其他結(jié)構(gòu)體的字段與方法,但是這個(gè)并不是真正意義上的繼承語法,外層結(jié)構(gòu)重寫隱式字段中的算法特定步驟后,無法動態(tài)綁定到“繼承”過來的算法的框架方法調(diào)用中,因此不能實(shí)現(xiàn)模板方法模式的語義。

(二)示例

本示例給出一種間接實(shí)現(xiàn)模板方法的方式,也比較符合模板方法模式的定義:

  • 將多個(gè)算法特定步驟組合成一個(gè)接口;
  • 基類隱式內(nèi)嵌算法步驟接口,同時(shí)調(diào)用算法步驟接口的各方法,實(shí)現(xiàn)算法的模板方法,此時(shí)基類內(nèi)嵌的算法步驟接口并沒有真正的處理行為;
  • 子類隱式內(nèi)嵌基類,并覆寫算法步驟接口的方法;
  • 通過工廠方法創(chuàng)建具體子類,并將自己的引用賦值給基類中算法步驟接口字段;

以演員裝扮為例,演員的裝扮是分為化妝,穿衣,配飾三步驟,三個(gè)步驟又根據(jù)不同角色的演員有所差別,因此演員基類實(shí)現(xiàn)裝扮的模板方法,對于化妝,穿衣,配飾的三個(gè)步驟,在子類演員中具體實(shí)現(xiàn),子類具體演員分為,男演員、女演員和兒童演員;

(三)演員基類

package templatemethod

import (
  "bytes"
  "fmt"
)

// IActor 演員接口
type IActor interface {
  DressUp() string // 裝扮
}

// dressBehavior 裝扮的多個(gè)行為,這里多個(gè)行為是私有的,通過DressUp模版方法調(diào)用
type dressBehavior interface {
  makeUp() string // 化妝
  clothe() string // 穿衣
  wear() string   // 配飾
}

// BaseActor 演員基類
type BaseActor struct {
  roleName      string // 扮演角色
  dressBehavior        // 裝扮行為
}

// DressUp 統(tǒng)一實(shí)現(xiàn)演員接口的DressUp模版方法,裝扮過程通過不同裝扮行為進(jìn)行擴(kuò)展
func (b *BaseActor) DressUp() string {
  buf := bytes.Buffer{}
  buf.WriteString(fmt.Sprintf("扮演%s的", b.roleName))
  buf.WriteString(b.makeUp())
  buf.WriteString(b.clothe())
  buf.WriteString(b.wear())
  return buf.String()
}

(四)具體演員

package templatemethod

// womanActor 擴(kuò)展裝扮行為的女演員
type womanActor struct {
  BaseActor
}

// NewWomanActor 指定角色創(chuàng)建女演員
func NewWomanActor(roleName string) *womanActor {
  actor := new(womanActor)    // 創(chuàng)建女演員
  actor.roleName = roleName   // 設(shè)置角色
  actor.dressBehavior = actor // 將女演員實(shí)現(xiàn)的擴(kuò)展裝扮行為,設(shè)置給自己的裝扮行為接口
  return actor
}

// 化妝
func (w *womanActor) makeUp() string {
  return "女演員涂著口紅,畫著眉毛;"
}

// 穿衣
func (w *womanActor) clothe() string {
  return "穿著連衣裙;"
}

// 配飾
func (w *womanActor) wear() string {
  return "帶著耳環(huán),手拎著包;"
}

// manActor 擴(kuò)展裝扮行為的男演員
type manActor struct {
  BaseActor
}

func NewManActor(roleName string) *manActor {
  actor := new(manActor)
  actor.roleName = roleName
  actor.dressBehavior = actor // 將男演員實(shí)現(xiàn)的擴(kuò)展裝扮行為,設(shè)置給自己的裝扮行為接口
  return actor
}

func (m *manActor) makeUp() string {
  return "男演員刮凈胡子,抹上發(fā)膠;"
}

func (m *manActor) clothe() string {
  return "穿著一身西裝;"
}

func (m *manActor) wear() string {
  return "帶上手表,抽著煙;"
}

// NewChildActor 擴(kuò)展裝扮行為的兒童演員
type childActor struct {
  BaseActor
}

func NewChildActor(roleName string) *childActor {
  actor := new(childActor)
  actor.roleName = roleName
  actor.dressBehavior = actor // 將兒童演員實(shí)現(xiàn)的擴(kuò)展裝扮行為,設(shè)置給自己的裝扮行為接口
  return actor
}

func (c *childActor) makeUp() string {
  return "兒童演員抹上紅臉蛋;"
}

func (c *childActor) clothe() string {
  return "穿著一身童裝;"
}

func (c *childActor) wear() string {
  return "手里拿著一串糖葫蘆;"
}

(五)測試程序

package templatemethod

import (
  "fmt"
  "testing"
)

func TestTemplateMethod(t *testing.T) {
  showActors(NewWomanActor("媽媽"), NewManActor("爸爸"), NewChildActor("兒子"))
}

// showActors 顯示演員的裝扮信息
func showActors(actors ...IActor) {
  for _, actor := range actors {
    fmt.Println(actor.DressUp())
  }
}

(六)運(yùn)行結(jié)果

=== RUN   TestTemplateMethod
扮演媽媽的女演員涂著口紅,畫著眉毛;穿著連衣裙;帶著耳環(huán),手拎著包;
扮演爸爸的男演員刮凈胡子,抹上發(fā)膠;穿著一身西裝;帶上手表,抽著煙;
扮演兒子的兒童演員抹上紅臉蛋;穿著一身童裝;手里拿著一串糖葫蘆;
--- PASS: TestTemplateMethod (0.00s)
PASS
【轉(zhuǎn)存】Go語言設(shè)計(jì)模式

訪問者模式

(一)概念

訪問者模式是一種行為設(shè)計(jì)模式,它能將算法與其所作用的對象隔離開來。允許你在不修改已有代碼的情況下向已有類層次結(jié)構(gòu)中增加新的行為。

訪問者接口需要根據(jù)被訪問者具體類,定義多個(gè)相似的訪問方法,每個(gè)具體類對應(yīng)一個(gè)訪問方法;每個(gè)被訪問者需要實(shí)現(xiàn)一個(gè)接受訪問者對象的方法,方法的實(shí)現(xiàn)就是去調(diào)用訪問者接口對應(yīng)該類的訪問方法;這個(gè)接受方法可以傳入不同目的訪問者接口的具體實(shí)現(xiàn),從而在不修改被訪問對象的前提下,增加新的功能;

(二)示例

公司中存在多種類型的員工,包括產(chǎn)品經(jīng)理、軟件工程師、人力資源等,他們的KPI指標(biāo)不盡相同,產(chǎn)品經(jīng)理為上線產(chǎn)品數(shù)量及滿意度,軟件工程師為實(shí)現(xiàn)的需求數(shù)及修改bug數(shù),人力資源為招聘員工的數(shù)量;公司要根據(jù)員工完成的KPI進(jìn)行表彰公示,同時(shí)根據(jù)KPI完成情況定薪酬,這些功能都是員工類職責(zé)之外的,不能修改員工本身的類,我們通過訪問者模式,實(shí)現(xiàn)KPI表彰排名及薪酬發(fā)放;文章來源地址http://www.zghlxwxcb.cn/news/detail-437722.html

(三)員工結(jié)構(gòu)

package visitor

import "fmt"

// Employee 員工接口
type Employee interface {
  KPI() string                    // 完成kpi信息
  Accept(visitor EmployeeVisitor) // 接受訪問者對象
}

// productManager 產(chǎn)品經(jīng)理
type productManager struct {
  name         string // 名稱
  productNum   int    // 上線產(chǎn)品數(shù)
  satisfaction int    // 平均滿意度
}

func NewProductManager(name string, productNum int, satisfaction int) *productManager {
  return &productManager{
    name:         name,
    productNum:   productNum,
    satisfaction: satisfaction,
  }
}

func (p *productManager) KPI() string {
  return fmt.Sprintf("產(chǎn)品經(jīng)理%s,上線%d個(gè)產(chǎn)品,平均滿意度為%d", p.name, p.productNum, p.satisfaction)
}

func (p *productManager) Accept(visitor EmployeeVisitor) {
  visitor.VisitProductManager(p)
}

// softwareEngineer 軟件工程師
type softwareEngineer struct {
  name           string // 姓名
  requirementNum int    // 完成需求數(shù)
  bugNum         int    // 修復(fù)問題數(shù)
}

func NewSoftwareEngineer(name string, requirementNum int, bugNum int) *softwareEngineer {
  return &softwareEngineer{
    name:           name,
    requirementNum: requirementNum,
    bugNum:         bugNum,
  }
}

func (s *softwareEngineer) KPI() string {
  return fmt.Sprintf("軟件工程師%s,完成%d個(gè)需求,修復(fù)%d個(gè)問題", s.name, s.requirementNum, s.bugNum)
}

func (s *softwareEngineer) Accept(visitor EmployeeVisitor) {
  visitor.VisitSoftwareEngineer(s)
}

// hr 人力資源
type hr struct {
  name       string // 姓名
  recruitNum int    // 招聘人數(shù)
}

func NewHR(name string, recruitNum int) *hr {
  return &hr{
    name:       name,
    recruitNum: recruitNum,
  }
}

func (h *hr) KPI() string {
  return fmt.Sprintf("人力資源%s,招聘%d名員工", h.name, h.recruitNum)
}

func (h *hr) Accept(visitor EmployeeVisitor) {
  visitor.VisitHR(h)
}

(四)員工訪問者

package visitor

import (
  "fmt"
  "sort"
)

// EmployeeVisitor 員工訪問者接口
type EmployeeVisitor interface {
  VisitProductManager(pm *productManager)     // 訪問產(chǎn)品經(jīng)理
  VisitSoftwareEngineer(se *softwareEngineer) // 訪問軟件工程師
  VisitHR(hr *hr)                             // 訪問人力資源
}

// kpi kpi對象
type kpi struct {
  name string // 完成kpi姓名
  sum  int    // 完成kpi總數(shù)量
}

// kpiTopVisitor 員工kpi排名訪問者
type kpiTopVisitor struct {
  top []*kpi
}

func (k *kpiTopVisitor) VisitProductManager(pm *productManager) {
  k.top = append(k.top, &kpi{
    name: pm.name,
    sum:  pm.productNum + pm.satisfaction,
  })
}

func (k *kpiTopVisitor) VisitSoftwareEngineer(se *softwareEngineer) {
  k.top = append(k.top, &kpi{
    name: se.name,
    sum:  se.requirementNum + se.bugNum,
  })
}

func (k *kpiTopVisitor) VisitHR(hr *hr) {
  k.top = append(k.top, &kpi{
    name: hr.name,
    sum:  hr.recruitNum,
  })
}

// Publish 發(fā)布KPI排行榜
func (k *kpiTopVisitor) Publish() {
  sort.Slice(k.top, func(i, j int) bool {
    return k.top[i].sum > k.top[j].sum
  })
  for i, curKPI := range k.top {
    fmt.Printf("第%d名%s:完成KPI總數(shù)%d\n", i+1, curKPI.name, curKPI.sum)
  }
}

// salaryVisitor 薪酬訪問者
type salaryVisitor struct{}

func (s *salaryVisitor) VisitProductManager(pm *productManager) {
  fmt.Printf("產(chǎn)品經(jīng)理基本薪資:1000元,KPI單位薪資:100元,")
  fmt.Printf("%s,總工資為%d元\n", pm.KPI(), (pm.productNum+pm.satisfaction)*100+1000)
}

func (s *salaryVisitor) VisitSoftwareEngineer(se *softwareEngineer) {
  fmt.Printf("軟件工程師基本薪資:1500元,KPI單位薪資:80元,")
  fmt.Printf("%s,總工資為%d元\n", se.KPI(), (se.requirementNum+se.bugNum)*80+1500)
}

func (s *salaryVisitor) VisitHR(hr *hr) {
  fmt.Printf("人力資源基本薪資:800元,KPI單位薪資:120元,")
  fmt.Printf("%s,總工資為%d元\n", hr.KPI(), hr.recruitNum*120+800)
}

(五)測試程序

package visitor

import "testing"

func TestVisitor(t *testing.T) {
  allEmployees := AllEmployees() // 獲取所有員工
  kpiTop := new(kpiTopVisitor)   // 創(chuàng)建KPI排行訪問者
  VisitAllEmployees(kpiTop, allEmployees)
  kpiTop.Publish() // 發(fā)布排行榜

  salary := new(salaryVisitor) // 創(chuàng)建薪酬訪問者
  VisitAllEmployees(salary, allEmployees)
}

// VisitAllEmployees 遍歷所有員工調(diào)用訪問者
func VisitAllEmployees(visitor EmployeeVisitor, allEmployees []Employee) {
  for _, employee := range allEmployees {
    employee.Accept(visitor)
  }
}

// AllEmployees 獲得所有公司員工
func AllEmployees() []Employee {
  var employees []Employee
  employees = append(employees, NewHR("小明", 10))
  employees = append(employees, NewProductManager("小紅", 4, 7))
  employees = append(employees, NewSoftwareEngineer("張三", 10, 5))
  employees = append(employees, NewSoftwareEngineer("李四", 3, 6))
  employees = append(employees, NewSoftwareEngineer("王五", 7, 1))
  return employees
}

(六)運(yùn)行結(jié)果

=== RUN   TestVisitor
第1名張三:完成KPI總數(shù)15
第2名小紅:完成KPI總數(shù)11
第3名小明:完成KPI總數(shù)10
第4名李四:完成KPI總數(shù)9
第5名王五:完成KPI總數(shù)8
人力資源基本薪資:800元,KPI單位薪資:120元,人力資源小明,招聘10名員工,總工資為2000元
產(chǎn)品經(jīng)理基本薪資:1000元,KPI單位薪資:100元,產(chǎn)品經(jīng)理小紅,上線4個(gè)產(chǎn)品,平均滿意度為7,總工資為2100元
軟件工程師基本薪資:1500元,KPI單位薪資:80元,軟件工程師張三,完成10個(gè)需求,修復(fù)5個(gè)問題,總工資為2700元
軟件工程師基本薪資:1500元,KPI單位薪資:80元,軟件工程師李四,完成3個(gè)需求,修復(fù)6個(gè)問題,總工資為2220元
軟件工程師基本薪資:1500元,KPI單位薪資:80元,軟件工程師王五,完成7個(gè)需求,修復(fù)1個(gè)問題,總工資為2140元
--- PASS: TestVisitor (0.00s)

到了這里,關(guān)于【轉(zhuǎn)存】Go語言設(shè)計(jì)模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【原型設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    【原型設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    原型模式(Prototype Pattern)是一種創(chuàng)建型設(shè)計(jì)模式,使你能夠復(fù)制已有對象,而無需使代碼依賴它們所屬的類,同時(shí)又能保證性能。 這種模式是實(shí)現(xiàn)了一個(gè)原型接口,該接口用于創(chuàng)建當(dāng)前對象的克隆。當(dāng)直接創(chuàng)建對象的代價(jià)比較大時(shí),則采用這種模式。 如果你需要復(fù)制一些對

    2023年04月24日
    瀏覽(26)
  • 【享元設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    【享元設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    享元模式(Flyweight Pattern),是一種結(jié)構(gòu)型設(shè)計(jì)模式。主要用于減少創(chuàng)建對象的數(shù)量,以減少內(nèi)存占用和提高性能。它摒棄了在每個(gè)對象中保存所有數(shù)據(jù)的方式,通過共享多個(gè)對象所共有的相同狀態(tài),讓你能在有限的內(nèi)存容量中載入更多對象。 當(dāng)程序需要生成數(shù)量巨大的相似

    2023年04月10日
    瀏覽(29)
  • 【模板方法設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    模板方法模式(Template Method Pattern)也叫模板模式,是一種行為型模式。它定義了一個(gè)抽象公開類,包含基本的算法骨架,而將一些步驟延遲到子類中,模板方法使得子類可以不改變算法的結(jié)構(gòu),只是重定義該算法的某些特定步驟。不同的子類以不同的方式實(shí)現(xiàn)這些抽象方法

    2024年02月01日
    瀏覽(22)
  • 【迭代器設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    【迭代器設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    迭代器模式(Iterator Pattern),是一種結(jié)構(gòu)型設(shè)計(jì)模式。給數(shù)據(jù)對象構(gòu)建一套按順序訪問集合對象元素的方式,而不需要知道數(shù)據(jù)對象的底層表示。 迭代器模式是與集合共存的,我們只要實(shí)現(xiàn)一個(gè)集合,就需要同時(shí)提供這個(gè)集合的迭代器,就像Java中的Collection,List、Set、Map等

    2023年04月17日
    瀏覽(15)
  • 【備忘錄設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    【備忘錄設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    備忘錄模式(Memento Pattern)是一種結(jié)構(gòu)型設(shè)計(jì)模式。這種模式就是在不破壞封裝的條件下,將一個(gè)對象的狀態(tài)捕捉(Capture)住,并放在外部存儲起來,從而可以在將來合適的時(shí)候把這個(gè)對象還原到存儲起來的狀態(tài)。備忘錄模式常常與命令模式和迭代子模式一同使用。 備忘錄模式

    2023年04月20日
    瀏覽(26)
  • 【中介者設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    【中介者設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    中介者模式(Mediator Pattern)是一種行為型模式。它限制對象之間的直接交互,它用一個(gè)中介對象來封裝一系列的動作,以讓對象之間進(jìn)行交流。中介者使各個(gè)對象不需要顯式地相互引用,從而使其耦合松散,而且可以獨(dú)立地改變它們之間的交互。 當(dāng)一些對象和其他對象緊密

    2023年04月19日
    瀏覽(28)
  • 【訪問者設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    【訪問者設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    訪問者模式(Visitor Pattern)是一種行為型模式。它封裝一個(gè)訪問者類,把各元素類的操作集合起來,目的是將數(shù)據(jù)結(jié)構(gòu)與數(shù)據(jù)操作分離。在不改變原有元素類數(shù)據(jù)結(jié)構(gòu)的前提下,改變了元素類的執(zhí)行算法。 當(dāng)某些較為穩(wěn)定的東西(數(shù)據(jù)結(jié)構(gòu)或算法),不想直接被改變但又想擴(kuò)

    2024年02月02日
    瀏覽(21)
  • 【觀察者設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    【觀察者設(shè)計(jì)模式詳解】C/Java/JS/Go/Python/TS不同語言實(shí)現(xiàn)

    觀察者模式(Observer Pattern)是一種行為型模式。它定義對象間的一種一對多的依賴關(guān)系,當(dāng)一個(gè)對象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對象都得到通知并被自動更新。 觀察者模式使用三個(gè)類Subject、Observer和Client。Subject對象帶有綁定觀察者到Client對象和從Client對象解綁觀察

    2023年04月21日
    瀏覽(24)
  • 【解釋器設(shè)計(jì)模式詳解】C/Java/Go/JS/TS/Python不同語言實(shí)現(xiàn)

    【解釋器設(shè)計(jì)模式詳解】C/Java/Go/JS/TS/Python不同語言實(shí)現(xiàn)

    解釋器模式(Interpreter Pattern)是一種行為型設(shè)計(jì)模式。這種模式實(shí)現(xiàn)了一個(gè)表達(dá)式接口,該接口解釋一個(gè)特定的上下文。這種模式常被用在 SQL 解析、符號處理引擎等。 解釋器模式常用于對簡單語言的編譯或分析實(shí)例中,為了掌握好它的結(jié)構(gòu)與實(shí)現(xiàn),必須先了解編譯原理中的

    2023年04月12日
    瀏覽(1388)
  • 【中級軟件設(shè)計(jì)師】—(針對上午題)二十三種設(shè)計(jì)模式(三十九)

    【中級軟件設(shè)計(jì)師】—(針對上午題)二十三種設(shè)計(jì)模式(三十九)

    簡單工廠模式代碼實(shí)現(xiàn)如下: ?? 意圖要背 工廠方法代碼實(shí)現(xiàn)如下: 抽象工廠模式代碼如下: 生成器模式代碼如下: 原型模式代碼實(shí)現(xiàn)如下: 單例模式代碼如下: 橋接模式代碼實(shí)現(xiàn)如下: 組合模式添加和刪除代碼實(shí)現(xiàn): 裝飾器模式代碼實(shí)現(xiàn): 外觀模式代碼實(shí)現(xiàn): 代理模

    2024年02月07日
    瀏覽(36)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包