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

单例模式 Singleton Pattern

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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类代理新的类工作。

image-20200614204438159

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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模式允许往一个对象里增加功能,提供了灵活拓展功能

实例:打印咖啡订单

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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())
}

运行结果

1
2
$ go run decorator.go
Soy Mocha Mocha Whip 4.81

Decorator模式使得增加中间件功能更加容易灵活,如 NSQ 的 http_api,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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

image-20200615132319929

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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")
}

运行结果

1
2
3
4
$ 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》