Cover photo

设计模式-Golang实现

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

单例模式 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 的 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

post image
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》