浅谈Go系统的层级和接口
一个系统至少会存三类接口:对外接口API、内部服务Service和数据服务DAO

一个系统大多会暴露一些对外的接口,我们称之为 API,例如 http api、rpc api、cli api等。项目中可能包含多个子模块,每个子模块就是一个子系统,这些子系统对外提供的接口我们称之为 Service。子模块中如果需要对数据进行访问,我们需要再提供一层数据接口,我们称之为 DAO。所以一个系统至少会存三类接口:API、Service、DAO。如果超过三层,可能写代码时候会比较麻烦,但是如果少于 3 层,又无法很好的对业务和数据层进行抽象。

API对外接口

API 是系统提供对外访问的接口。API 可以存在不同的种类,例如 http 接口、GRPC 接口。也可以存在不同的版本,例如 v1、v2等。

internal
├── api
│   ├── base.go
│   └── v1
│       └── hello.go

Module 模块

一个系统可能包含若干个模块,例如一个电商系统包含用户模块、订单模块、商品模块等。一个模块相当于一个子系统。

internal
├── module
│   ├── system
│   ├── order
│   ├── product
│   └── user

Service 服务

一个模块必然需要对外提供一些接口,这些接口定义代码放在 service.go 文件中,参考如下:

//go:generate mockgen -source $GOFILE -destination ./service_mock.go -package $GOPACKAGE
package system

import "context"

type Service interface {
		CreateUser(ctx context.Context, req *CreateUserRequest) (*CreateUserResponse, error)
	  GetUserById(ctx context.Context, id int64) (*GetUserResponse, error)
}

将 service 接口实现的代码放在 service 目录中。

├── module
│   ├── user
│   │   ├── service
│   │   │   └── service.go
│   │   ├── service.go
│   │   ├── service_mock.go

DAO 数据接口

一个模块必然存在对数据的访问。例如,将数据保存到数据库,将文件保存到磁盘、OSS等,调用GRPC 接口等。对数据的访问需要定义在 DAO 中,这些接口定义代码放在 dao.go 文件中,参考如下:

//go:generate mockgen -source $GOFILE -destination ./dao_mock.go -package $GOPACKAGE
package user

import (
	"context"
)

type DAO interface {
	CreateUser(ctx context.Context, m *User) error
	GetUser(ctx context.Context, req *model.GetUserReq) (*User, error)
	GetUserById(ctx context.Context, id int64) (*User, error)
}

将 dao 接口实现的代码放在 dao目录中

├── module
│   ├── system
│   │   ├── dao
│   │   │   └── dao.go
│   │   ├── dao.go
│   │   ├── dao_mock.go

最后修改于 2024-08-10

此篇文章的评论功能已经停用。