Go语言中如何封装同一API的多并发实现?
嘿,我懂你遇到的问题了——想给同一API的多个实现抽离公共字段和方法契约,但Go没有传统的类继承,直接写“父类型”行不通对吧?别担心,咱们用Go的接口定义方法契约 + 嵌入结构体复用公共字段的组合就能完美实现你要的效果!
核心思路
Go的设计哲学里没有继承,但它的接口可以强制所有实现遵守统一的方法规范,而结构体嵌入可以让多个类型复用同一套公共成员变量,两者结合就相当于实现了你想要的“父类型”效果。
具体实现步骤
1. 用接口定义所有实现必须遵守的方法契约
首先,我们定义一个接口,把所有存储实现必须具备的方法都列进去——这就是你的API统一契约:
// DataStore 所有存储实现的统一接口,定义必须实现的方法 type DataStore interface { Get(id int) (string, error) // 根据ID获取数据 Save(id int, data string) error // 保存数据 Delete(id int) error // 删除数据 }
2. 定义基础结构体存放公共成员变量
接下来,创建一个基础结构体,把所有实现共有的成员(比如日志实例、超时配置这类通用属性)放进去:
import "log" import "time" // BaseStore 存放所有DataStore实现共有的成员变量 type BaseStore struct { Logger *log.Logger // 所有实现共用的日志组件 Timeout time.Duration // 所有实现共用的超时配置 }
3. 具体实现嵌入基础结构体并实现接口
每个具体的存储实现(SQL、XML)都嵌入BaseStore,这样它们就能直接使用公共成员,同时实现DataStore接口的所有方法。
示例1:SQL数据库实现
import "database/sql" // SQLStore 基于SQL的存储实现 type SQLStore struct { BaseStore // 嵌入基础结构体,自动继承其所有成员 DB *sql.DB // SQL实现特有的数据库连接 } // 实现DataStore接口的Get方法 func (s *SQLStore) Get(id int) (string, error) { // 可以直接使用BaseStore的Logger s.Logger.Println("SQLStore: 正在获取ID", id, "的数据") // 具体SQL查询逻辑 var data string err := s.DB.QueryRow("SELECT data FROM items WHERE id = ?", id).Scan(&data) return data, err } // 实现Save方法 func (s *SQLStore) Save(id int, data string) error { s.Logger.Println("SQLStore: 正在保存ID", id, "的数据") _, err := s.DB.Exec("INSERT INTO items (id, data) VALUES (?, ?)", id, data) return err } // 实现Delete方法 func (s *SQLStore) Delete(id int) error { s.Logger.Println("SQLStore: 正在删除ID", id, "的数据") _, err := s.DB.Exec("DELETE FROM items WHERE id = ?", id) return err }
示例2:XML文件存储实现
import "os" import "strconv" // XMLStore 基于XML文件的存储实现 type XMLStore struct { BaseStore // 同样嵌入基础结构体 FilePath string // XML实现特有的文件路径 } // 实现DataStore接口的Get方法 func (x *XMLStore) Get(id int) (string, error) { x.Logger.Println("XMLStore: 正在获取ID", id, "的数据") // 具体XML读取逻辑(这里简化示例) file, err := os.Open(x.FilePath) if err != nil { return "", err } defer file.Close() // 解析XML并返回对应数据(示例返回模拟值) return "xml-data-" + strconv.Itoa(id), nil } // 实现Save方法 func (x *XMLStore) Save(id int, data string) error { x.Logger.Println("XMLStore: 正在保存ID", id, "的数据") // 具体XML写入逻辑(示例省略) return nil } // 实现Delete方法 func (x *XMLStore) Delete(id int) error { x.Logger.Println("XMLStore: 正在删除ID", id, "的数据") // 具体XML删除逻辑(示例省略) return nil }
4. 统一使用接口实现多态
现在你可以把任何实现了DataStore接口的实例当成接口类型来使用,实现完美的多态:
import "fmt" func main() { // 初始化公共日志组件 logger := log.New(os.Stdout, "[STORE] ", log.LstdFlags) // 初始化SQL存储实例 db, _ := sql.Open("sqlite3", "./test.db") sqlStore := &SQLStore{ BaseStore: BaseStore{ Logger: logger, Timeout: 5 * time.Second, }, DB: db, } // 初始化XML存储实例 xmlStore := &XMLStore{ BaseStore: BaseStore{ Logger: logger, Timeout: 5 * time.Second, }, FilePath: "./data.xml", } // 统一用DataStore接口操作,无需关心具体实现 useStore(sqlStore) useStore(xmlStore) } // 接收DataStore接口,处理通用逻辑 func useStore(store DataStore) { err := store.Save(1, "测试数据") if err != nil { log.Fatal(err) } data, err := store.Get(1) if err != nil { log.Fatal(err) } fmt.Println("获取到的数据:", data) }
额外小技巧
如果公共成员需要复杂初始化,可以给BaseStore写一个构造函数,这样每个具体实现的初始化会更简洁:
func NewBaseStore(logger *log.Logger, timeout time.Duration) BaseStore { return BaseStore{ Logger: logger, Timeout: timeout, } } // 初始化SQLStore时就可以这么用 sqlStore := &SQLStore{ BaseStore: NewBaseStore(logger, 5*time.Second), DB: db, }
内容的提问来源于stack exchange,提问作者Scott Deerwester
相关产品推荐
相关产品推荐

