快速了解 GO之接口解耦

更多个人笔记见:
github个人笔记仓库
gitee 个人笔记仓库

个人学习,学习过程中还会不断补充~ (后续会更新在github上)

文章目录

接口解耦的作用是便于切换三方库(项目需要或者三方库废弃不维护)等时候,不用大量修改代码而构建的设计

例子分析解耦

xorm 和 gorm 如果希望互相切换,使用上区别在于二者创建数据库的方法不同,xorm 为 Insert,gorm 为 Create

一般的构建思路

构建 xorm 的:

GO 复制代码
type XormDB struct{
	db *xorm.Session
	...	
}

type Trade struct {
	*XormDB
	...
}

func (t *Trade) InsertTrade( data interface{})  {
	t.db.Insert(data) 
	...
}

如果现在需要构建 gorm 的,就需要所有的替换成下面这样,同时接口等也都需要改变

GO 复制代码
type GormDB struct{
	db *Gorm.Session
	...	
}

type Trade struct {
	*GormDB
	...
}

func (t *Trade) InsertTrade( data interface{}) error  {
	t.db.Create(data) 
	...
}
解耦的构建思路
  • 所以采用接口的方法:
GO 复制代码
//初始化 xorm
type DBer interface {
	Insert(ctx context.Context, instance interface{})  //定义统一的 insert方法
}

type XormDB struct {
	db *xorm.Session
}
func (xorm *XormDB) Insert (ctx contesxt.COntext,instance ... interfaceP{}){
	xorm.db.Context(ctx).Insert(instance)
}

//初始化 gorm
type GormDB struct {
	db *gorm.DB
}
func (gorm *GormDB) Insert(ctx context.Context,instance... interface{}){
	gorm.db.Context(ctx).Create(instance)
}

//实际业务结构体
type Trade struct {
	db DBer
}
//初始化对应的数据库
func (t *Trade) AddDB(db DBer){
	t.db = db
}
//只要完成了 insert 方法就是可以的
func (t *Trade) AddTrade(ctx context.Context,instance interface{}){
	t.db.Insert(ctx,instance)
}

这样只用自己定义满足 DBer 接口的结构体,加入新的三方库就都是可以的,因为都是统一调用 Insert 方法

  • 另外一个同样解耦构建的例子:
    从底向上实现
GO 复制代码
// 定义数据访问层接口,这是一个统一的接口
type Repository interface {
    Create(entity interface{}) error
    //下面几个方法如果添加那么也要给GormRepository和XormRepository补上对应的 方法
    //FindByID(id uint, out interface{}) error
    //Update(entity interface{}) error
    //Delete(entity interface{}) error
}

注意:一般这几个不会放在同一个文件或者层次中的,比如model 层或者 dao 层等等,会在实际项目中划分开

GO 复制代码
// GORM实现
type GormRepository struct {
    db *gorm.DB
}

func (r *GormRepository) Create(entity interface{}) error {
    return r.db.Create(entity).Error
}

// XORM实现
type XormRepository struct {
    engine *xorm.Engine
}

func (r *XormRepository) Create(entity interface{}) error {
    _, err := r.engine.Insert(entity)
    return err
}

具体业务逻辑:

Go 复制代码
// 业务层只依赖Repository接口
type UserService struct {
    repo Repository
}

func NewUserService(repo Repository) *UserService {
    return &UserService{repo: repo}    //初始化对应的实例
}

func (s *UserService) CreateUser(user *User) error {
    return s.repo.Create(user)  //调用接口对应的 Create 函数就可以了
}

初始化的时候决定具体的实现,使用自己定义的结构体,对应 gorm 的GormRepository还是对应 xorm 的XormRepository

所以除去结构体的修改和补充,其实只要在这个地方进行改动就可以了

GO 复制代码
//使用GORM
db := gorm.Open(...)
service := NewUserService(&GormRepository{db: db})

//使用XORM
engine, _ := xorm.NewEngine(...)
service := NewUserService(&XormRepository{engine: engine})

(补充)工厂模式切换:

go 复制代码
func NewRepository(dbType string, conn interface{}) (Repository, error) {
    switch dbType {
    case "gorm":
        return &GormRepository{db: conn.(*gorm.DB)}, nil
    case "xorm":
        return &XormRepository{engine: conn.(*xorm.Engine)}, nil
    default:
        return nil, errors.New("unsupported database type")
    }
}

解耦的好处:

  • 切换ORM(例子中是 ORM)只需修改初始化代码
  • 易于单元测试(mock Repository)
  • 不一定固定依赖某个三方库
相关推荐
Scott9999HH1 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
GetcharZp2 小时前
抛弃低效SSH!这套Ansible+Web可视化神器,让你天天准点下班!
后端
码智社2 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海3 小时前
python 列表、元组、集合和字典
开发语言·python
克里斯蒂亚诺更新3 小时前
ruoyi角色权限的对应关系
笔记
萧瑟余晖3 小时前
JDK 26 新特性详解
java·开发语言
马优晨4 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
weixin_446260855 小时前
HACO:面向动态部署环境的对冲式智能计算可靠多智能体调度框架
后端·python·flask
a1117765 小时前
2FA 验证码生成器(github登录验证 app)
笔记·学习
我的xiaodoujiao6 小时前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest