# 设计模式-Golang实现

By [明晶](https://paragraph.com/@0x8ffa8517805be4d4a72bc830286d91cc8b03c326) · 2022-02-05

---

设计模式一般遵守 “开放封闭” 原则，即对拓展开放，对修改封闭。

### 单例模式 Singleton Pattern

保证一个类只有一个实例，并提供全局调用。它是最简单的设计模式，也是少有的违反 “开放封闭” 的模式。常用实例：数据库读写工具类、配置文件读取

    type SingleTon struct{}
    
    var mu sync.Mutex
    var instance *SingleTon
    
    func getInstance() *SingleTon {
        mu.Lock()
        defer mu.Unlock()
        if instance == nil {
            instance = &SingleTon{}
        }
        return instance
    }
    
    func getInstance2() *SingleTon {
        if instance == nil {
            mu.Lock()
            if instance == nil {
                instance = &SingleTon{}
            }
            mu.Unlock()
        }
        return instance
    }
    
    var once sync.Once
    
    func getInstance3() *SingleTon {
        once.Do(func() {
            instance = &SingleTon{}
        })
        return instance
    }
    

### Adapter模式

Adapter模式 是将一个类的接口转换成另一个类所期待的接口，使两个因为接口不兼容而不能一起工作的两个类能够一起工作。一言蔽之：使新的类重用旧的类使用的接口。其实就是用adapter类代理新的类工作。

    func main() {
        duck := &MallardDuck{} // 接口方法集
        turkey := &WildTurkey{}
        turkeyAdapter := &TurkeyAdatper{turkey: turkey}
    
        fmt.Println("The Turkey says...")
        turkey.gobble()
        turkey.fly()
    
        fmt.Println("The Duck says...")
        testDuck(duck)
    
        fmt.Println("The Turkey dapter says...")
        testDuck(turkeyAdapter)
    }
    // turkey通过adapter代理也可以使用testDuck接口
    func testDuck(duck Duck) { 
        duck.quack()
        duck.fly()
    }
    
    type Duck interface {
        quack()
        fly()
    }
    
    type MallardDuck struct {
    }
    
    func (d *MallardDuck) quack() {
        fmt.Println("Quack")
    }
    func (d *MallardDuck) fly() {
        fmt.Println("I am flying")
    }
    
    type Turkey interface {
        gobble()
        fly()
    }
    type WildTurkey struct {
    }
    
    func (t *WildTurkey) gobble() {
        fmt.Println("Gobble gobble")
    }
    func (t *WildTurkey) fly() {
        fmt.Println("I am flying a short distance")
    }
    
    type TurkeyAdatper struct {
        turkey Turkey
    }
    
    func (a *TurkeyAdatper) quack() {
        a.turkey.gobble()
    }
    func (a *TurkeyAdatper) fly() {
        a.turkey.fly()
    }
    

当然adapter也可以使功能更容易扩展，如Adapter模式在android里有一个最典型的用例是 RecycleView或Listview的adapter，有了adapter模式，android开发者可以自定义各种list view。哈哈，这不就是遵守了"开放"原则吗。

### Decorator模式

Decorator模式允许往一个对象里增加功能，提供了灵活拓展功能

实例：打印咖啡订单

    func decorate(beverage Beverage, ds ...Decorator) Beverage {
        for _, decorate := range ds {
            beverage = decorate(beverage)
        }
        return beverage
    }
    type Decorator func(Beverage) Beverage
    type Beverage func() (string, float64)
    
    func main() {
        beverage := func() (name string, cost float64) {
            name = "Soy"
            cost = 1.44
            return
        }
        mocha := func(beverage Beverage) Beverage {
            return func() (string, float64) {
                name, cost := beverage()
                return name + " Mocha", cost + 1.19
            }
        }
        whip := func(beverage Beverage) Beverage {
            return func() (string, float64) {
                name, cost := beverage()
                return name + " Whip", cost + 0.99
            }
        }
        beverage = decorate(beverage, mocha, mocha, whip)
        fmt.Println(beverage())
    }
    

运行结果

    $ go run decorator.go
    Soy Mocha Mocha Whip 4.81
    

Decorator模式使得增加中间件功能更加容易灵活，如 [NSQ](https://nsq.io/) 的 http\_api，

    router.Handle("POST", "/topic/create", http_api.Decorate(s.doCreateTopic, log, http_api.V1))
    func Decorate(f APIHandler, ds ...Decorator) httprouter.Handle {
        decorated := f
        for _, decorate := range ds {
            decorated = decorate(decorated)
        }
        return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
            decorated(w, req, ps)
        }
    }
    type Decorator func(APIHandler) APIHandler
    type APIHandler func(http.ResponseWriter, *http.Request, httprouter.Params) (interface{}, error)
    

### 观察者模式 Observer Pattern

Publishers + Subscribers = Observer Pattern

![](https://storage.googleapis.com/papyrus_images/bd8ded4ceefe3362319c81ed15e8573e745d1f3902ddd6f93bb3fc5070b0a272.png)

    func main() {
        weatherData := &WeatherData{
            observers: []Observer{},
        }
        currentConditionsDisplay := &CurrentConditionsDisplay{}
        weatherData.registerObserver(currentConditionsDisplay)
    
        weatherData.set(80, 65, 30.4)
        weatherData.set(82, 70, 29.2)
        weatherData.set(78, 90, 29.2)
    }
    
    type Observer interface {
        update(temperature float64, humidity float64, pressure float64)
    }
    type Subject interface {
        registerObserver(Observer)
        removeObserver(Observer)
        notifyObservers()
    }
    
    type WeatherData struct {
        temperature float64
        humidity    float64
        pressure    float64
        observers   []Observer
    }
    
    func (w *WeatherData) registerObserver(o Observer) {
        w.observers = append(w.observers, o)
    
    }
    func (w *WeatherData) removeObserver(o Observer) {
        for i, observer := range w.observers {
            if observer == o {
                lastIndex := len(w.observers) - 1
                w.observers[i], w.observers[lastIndex] = w.observers[lastIndex], w.observers[i]
                w.observers = w.observers[:lastIndex]
                break
            }
        }
    }
    func (w *WeatherData) set(temperature float64, humidity float64, pressure float64) {
        w.temperature = temperature
        w.humidity = humidity
        w.pressure = pressure
        w.notifyObservers()
    }
    func (w *WeatherData) notifyObservers() {
        for _, o := range w.observers {
            o.update(w.temperature, w.humidity, w.pressure)
        }
    }
    
    type CurrentConditionsDisplay struct {
        temperature float64
        humidity    float64
        pressure    float64
    }
    func (d *CurrentConditionsDisplay) update(temperature float64, humidity float64, pressure float64) {
        d.temperature = temperature
        d.humidity = humidity
        d.pressure = pressure
        fmt.Println("Current conditions: ", d.temperature, "F degrees ", d.humidity, "% humidity")
    }
    

运行结果

    $ go run observer.go
    Current conditions:  80 F degrees  65 % humidity
    Current conditions:  82 F degrees  70 % humidity
    Current conditions:  78 F degrees  90 % humidity
    

参考
--

《head first design patterns》

---

*Originally published on [明晶](https://paragraph.com/@0x8ffa8517805be4d4a72bc830286d91cc8b03c326/golang)*
