

设计模式中的策略模式与Go语言中的一个小技巧
source link: https://zhuanlan.zhihu.com/p/370192367
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

设计模式中的策略模式与Go语言中的一个小技巧
很早以前,我对设计模式是不屑一顾的。
现在我不会这么傲慢了。设计模式,说白了就是写代码的套路。天才倒是不劳烦设计模式的总结者,可是咱们普通人还是能够从中吸取到很多养分的。
设计模式分成三大类:创建型、结构性、行为型。
其中创建型和结构型比较重要。而行为型,就比较散乱。在lambda(以及函数式编程)的帮助下,很多套路都已经变得平凡而普通。
今天说说策略模式:
代码来自:https://zhuanlan.zhihu.com/p/274421641
package strategy
import (
"fmt"
"io/ioutil"
"os"
)
// StorageStrategy 存储策略
type StorageStrategy interface {
Save(name string, data []byte) error
}
var strategys = map[string]StorageStrategy{
"file": &fileStorage{},
"encrypt_file": &encryptFileStorage{},
}
// NewStorageStrategy NewStorageStrategy
func NewStorageStrategy(t string) (StorageStrategy, error) {
s, ok := strategys[t]
if !ok {
return nil, fmt.Errorf("not found StorageStrategy: %s", t)
}
return s, nil
}
// FileStorage 保存到文件
type fileStorage struct{}
// Save Save
func (s *fileStorage) Save(name string, data []byte) error {
return ioutil.WriteFile(name, data, os.ModeAppend)
}
// encryptFileStorage 加密保存到文件
type encryptFileStorage struct{}
// Save Save
func (s *encryptFileStorage) Save(name string, data []byte) error {
// 加密
data, err := encrypt(data)
if err != nil {
return err
}
return ioutil.WriteFile(name, data, os.ModeAppend)
}
func encrypt(data []byte) ([]byte, error) {
// 这里实现加密算法
return data, nil
}
存储策略有两种(可有有更多种),每种策略是用一个类来实现的。这当然可以说是对Java的模仿。
那么假如某种策略特别简单,简单到一个函数就可以表达呢?
现在的策略是interface { Save(name string, data []byte) error },是一个接口,那么我们是否可以把策略的类型定为 func Save(name string, data []byte) error(一个函数)呢?
也不是不可以,但那样一来,如果这个函数比较复杂,需要引用外部的变量(比如内部拥有状态),或者说,是个闭包。我们就会发现,这个函数和相关的变量散落在文件中,散发出不好闻的味道。
于是,我们会发现接口适合于复杂的情形,而匿名函数适合于简单的情形。
但是小孩子才做选择,成年人选择全都要。Go语言当然也做得到:
package strategy
import (
"fmt"
"io/ioutil"
"os"
)
// StorageStrategy 存储策略
type StorageStrategy interface {
Save(name string, data []byte) error
}
// 简单的策略函数 类型
type StorageStrategySaveFunc func(string, []byte) error
// 魔法发生在这里:简单策略函数类型实现了上面的接口
func (f StorageStrategySaveFunc) Save(name string, data []byte) error {
return f(name, data)
}
var strategys = map[string]StorageStrategy{
// 这里发生了类型转换
"file": StorageStrategySaveFunc(fileStorageSave),
"encrypt_file": &encryptFileStorage{},
}
// NewStorageStrategy NewStorageStrategy
func NewStorageStrategy(t string) (StorageStrategy, error) {
s, ok := strategys[t]
if !ok {
return nil, fmt.Errorf("not found StorageStrategy: %s", t)
}
return s, nil
}
// FileStorage 保存到文件
func fileStorageSave(name string, data []byte) error {
// 这个算法足够简单,我们可以直接一个函数写完
return ioutil.WriteFile(name, data, os.ModeAppend)
}
// encryptFileStorage 加密保存到文件
type encryptFileStorage struct {
blocks []byte // 假设这个算法足够复杂以至于我们必须有一些内部变量
}
// Save Save
func (s *encryptFileStorage) Save(name string, data []byte) error {
// 加密
data, err := encrypt(data)
if err != nil {
return err
}
return ioutil.WriteFile(name, data, os.ModeAppend)
}
func encrypt(data []byte) ([]byte, error) {
// 这里实现加密算法
return data, nil
}
眼尖的同学会发现,这不就是http包的HandleFunc么。
当然是的。(不过你之前发现http包用到了策略模式了吗?)
(没发现也好。使用设计模式的最高境界就是自己都没意识到自己使用了设计模式)
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK