Go 常用的設(shè)計(jì)模式

常用設(shè)計(jì)模式

1. 單例模式:


package singleton

import (
    "sync"
)

type singleton struct {
}

var ins *singleton
var once sync.Once

func GetInsOr() *singleton {
    once.Do(func() {
        ins = &singleton{}
    })
    return ins
}

2. 簡單工廠模式


type Person struct {
  Name string
  Age int
}

func (p Person) Greet() {
  fmt.Printf("Hi! My name is %s", p.Name)
}

func NewPerson(name string, age int) *Person {
  return &Person{
    Name: name,
    Age: age,
  }
}

3. 抽象工廠模式

它返回的是接口而不是結(jié)構(gòu)體。


type Person interface {
  Greet()
}

type person struct {
  name string
  age int
}

func (p person) Greet() {
  fmt.Printf("Hi! My name is %s", p.name)
}

// Here, NewPerson returns an interface, and not the person struct itself
func NewPerson(name string, age int) Person {
  return person{
    name: name,
    age: age,
  }
}

4. 工廠方法模式


type Person struct {
  name string
  age int
}

func NewPersonFactory(age int) func(name string) Person {
  return func(name string) Person {
    return Person{
      name: name,
      age: age,
    }
  }
}

5. 策略模式

在項(xiàng)目開發(fā)中,我們經(jīng)常要根據(jù)不同的場景,采取不同的措施,也就是不同的策略。比如,假設(shè)我們需要對(duì) a、b 這兩個(gè)整數(shù)進(jìn)行計(jì)算,根據(jù)條件的不同,需要執(zhí)行不同的計(jì)算方式。為了解耦,需要使用策略模式,定義一些獨(dú)立的類來封裝不同的算法,每一個(gè)類封裝一個(gè)具體的算法(即策略)。


package strategy

// 策略模式

// 定義一個(gè)策略類
type IStrategy interface {
  do(int, int) int
}

// 策略實(shí)現(xiàn):加
type add struct{}

func (*add) do(a, b int) int {
  return a + b
}

// 策略實(shí)現(xiàn):減
type reduce struct{}

func (*reduce) do(a, b int) int {
  return a - b
}

// 具體策略的執(zhí)行者
type Operator struct {
  strategy IStrategy
}

// 設(shè)置策略
func (operator *Operator) setStrategy(strategy IStrategy) {
  operator.strategy = strategy
}

// 調(diào)用策略中的方法
func (operator *Operator) calculate(a, b int) int {
  return operator.strategy.do(a, b)
}

6. 模板模式

模板模式就是將一個(gè)類中能夠公共使用的方法放置在抽象類中實(shí)現(xiàn),將不能公共使用的方法作為抽象方法,強(qiáng)制子類去實(shí)現(xiàn),這樣就做到了將一個(gè)類作為一個(gè)模板,讓開發(fā)者去填充需要填充的地方。


package template

import "fmt"

type Cooker interface {
  fire()
  cooke()
  outfire()
}

// 類似于一個(gè)抽象類
type CookMenu struct {
}

func (CookMenu) fire() {
  fmt.Println("開火")
}

// 做菜,交給具體的子類實(shí)現(xiàn)
func (CookMenu) cooke() {
}

func (CookMenu) outfire() {
  fmt.Println("關(guān)火")
}

// 封裝具體步驟
func doCook(cook Cooker) {
  cook.fire()
  cook.cooke()
  cook.outfire()
}

type XiHongShi struct {
  CookMenu
}

func (*XiHongShi) cooke() {
  fmt.Println("做西紅柿")
}

type ChaoJiDan struct {
  CookMenu
}

func (ChaoJiDan) cooke() {
  fmt.Println("做炒雞蛋")
}

7. 代理模式

可以為另一個(gè)對(duì)象提供一個(gè)替身或者占位符,以控制對(duì)這個(gè)對(duì)象的訪問。


package proxy

import "fmt"

type Seller interface {
  sell(name string)
}

// 火車站
type Station struct {
  stock int //庫存
}

func (station *Station) sell(name string) {
  if station.stock > 0 {
    station.stock--
    fmt.Printf("代理點(diǎn)中:%s買了一張票,剩余:%d \n", name, station.stock)
  } else {
    fmt.Println("票已售空")
  }

}

// 火車代理點(diǎn)
type StationProxy struct {
  station *Station // 持有一個(gè)火車站對(duì)象
}

func (proxy *StationProxy) sell(name string) {
  if proxy.station.stock > 0 {
    proxy.station.stock--
    fmt.Printf("代理點(diǎn)中:%s買了一張票,剩余:%d \n", name, proxy.station.stock)
  } else {
    fmt.Println("票已售空")
  }
}

8. 選項(xiàng)模式


package options

import (
  "time"
)

type Connection struct {
  addr    string
  cache   bool
  timeout time.Duration
}

const (
  defaultTimeout = 10
  defaultCaching = false
)

type options struct {
  timeout time.Duration
  caching bool
}

// Option overrides behavior of Connect.
type Option interface {
  apply(*options)
}

type optionFunc func(*options)

func (f optionFunc) apply(o *options) {
  f(o)
}

func WithTimeout(t time.Duration) Option {
  return optionFunc(func(o *options) {
    o.timeout = t
  })
}

func WithCaching(cache bool) Option {
  return optionFunc(func(o *options) {
    o.caching = cache
  })
}

// Connect creates a connection.
func NewConnect(addr string, opts ...Option) (*Connection, error) {
  options := options{
    timeout: defaultTimeout,
    caching: defaultCaching,
  }

  for _, o := range opts {
    o.apply(&options)
  }

  return &Connection{
    addr:    addr,
    cache:   options.caching,
    timeout: options.timeout,
  }, nil
}

選項(xiàng)模式通常適用于以下場景:

  • 結(jié)構(gòu)體參數(shù)很多,創(chuàng)建結(jié)構(gòu)體時(shí),我們期望創(chuàng)建一個(gè)攜帶默認(rèn)值的結(jié)構(gòu)體變量,并選擇性修改其中一些參數(shù)的值。
  • 結(jié)構(gòu)體參數(shù)經(jīng)常變動(dòng),變動(dòng)時(shí)我們又不想修改創(chuàng)建實(shí)例的函數(shù)。例如:結(jié)構(gòu)體新增一個(gè) retry 參數(shù),但是又不想在 NewConnect 入?yún)⒘斜碇刑砑觬etry int這樣的參數(shù)聲明。

參考文章

  • Go 語言項(xiàng)目開發(fā)實(shí)戰(zhàn)/設(shè)計(jì)模式
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容