今天小编为大家分享基于DDD的golang实现,DDD即领域驱动设计,该模式也算是比较热门的话题了。希望通过本篇文章,大家能够掌握DDD模式,能对大家有所帮助。
领域驱动设计模式算是比较热门的话题了。
领域驱动设计(DDD)是一种软件开发方法,通过将实现与不断演变的模型相连接,简化了开发人员面临的复杂性。
本文不会重点去解释Golang中实现DDD的相关理念,而是作者根据自己的研究对DDD的理解。
什么是DDD?
以下是考虑使用DDD的原因:
- 提供解决困难问题的原则和模式
- 将复杂的设计基于领域模型
- 在技术和领域专家之间发起创造性的协作,以迭代地完善解决领域问题的概念模型
DDD包含4个层:
- Domain:这是定义应用程序的域和业务逻辑的地方
- Infrastructure:此层包含独立于我们的应用程序而存在的所有内容:外部库,数据库引擎等。
- Application:该层用作域和界面层之间的通道。将请求从接口层发送到域层,由域层处理请求并返回响应。
- Interface:该层包含与其他系统交互的所有内容,例如Web服务,RMI接口或Web应用程序以及批处理前端。

开始
我们将构建一个食物推荐API。
首先要做的是初始化依赖关系管理。我们将使用go.mod。在根目录(路径:food-app /)中,初始化go.mod:
go mod init food-app
项目的组织结构:

在该应用中,我们将使用postgres和redis数据库持久化数据。先定义一个含有连接信息的.env文件。
.env文件内容:
#PostgresAPP_ENV=localAPI_PORT=8888DB_HOST=127.0.0.1DB_DRIVER=postgresACCESS_SECRET=98hbun98hREFRESH_SECRET=786dfdbjhsbDB_USER=stevenDB_PASSWORD=passwordDB_NAME=food-appDB_PORT=5432#Mysql#DB_HOST=127.0.0.1#DB_DRIVER=mysql#DB_USER=steven#DB_PASSWORD=here#DB_NAME=food-app#DB_PORT=3306#Postgres Test DBTEST_DB_DRIVER=postgresTEST_DB_HOST=127.0.0.1TEST_DB_PASSWORD=passwordTEST_DB_USER=stevenTEST_DB_NAME=food-app-testTEST_DB_PORT=5432#RedisREDIS_HOST=127.0.0.1REDIS_PORT=6379REDIS_PASSWORD=
该文件应位于根目录中(路径:food-app /)
Domain层
我们将首先考虑领域。
该域具有几种模式。其中一些是:实体,值,存储库,服务等。
由于我们在此处构建的应用比较简单,因此我们仅考虑两种域模式:实体和存储库。
实体
这是我们定义“Schema”的地方。
例如,我们可以定义用户的结构。将该实体视为域的蓝图。
package entityimport ("food-app/infrastructure/security""github.com/badoux/checkmail""html""strings""time")type User struct {ID uint64 `gorm:"primary_key;auto_increment" json:"id"`FirstName string `gorm:"size:100;not null;" json:"first_name"`LastName string `gorm:"size:100;not null;" json:"last_name"`Email string `gorm:"size:100;not null;unique" json:"email"`Password string `gorm:"size:100;not null;" json:"password"`CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`DeletedAt *time.Time `json:"deleted_at,omitempty"`}type PublicUser struct {ID uint64 `gorm:"primary_key;auto_increment" json:"id"`FirstName string `gorm:"size:100;not null;" json:"first_name"`LastName string `gorm:"size:100;not null;" json:"last_name"`}//BeforeSave is a gorm hookfunc (u *User) BeforeSave() error {hashPassword, err := security.Hash(u.Password)if err != nil {return err}u.Password = string(hashPassword)return nil}type Users []User//So that we dont expose the user's email address and password to the worldfunc (users Users) PublicUsers() []interface{} {result := make([]interface{}, len(users))for index, user := range users {result[index] = user.PublicUser()}return result}//So that we dont expose the user's email address and password to the worldfunc (u *User) PublicUser() interface{} {return &PublicUser{ID: u.ID,FirstName: u.FirstName,LastName: u.LastName,}}func (u *User) Prepare() {u.FirstName = html.EscapeString(strings.TrimSpace(u.FirstName))u.LastName = html.EscapeString(strings.TrimSpace(u.LastName))u.Email = html.EscapeString(strings.TrimSpace(u.Email))u.CreatedAt = time.Now()u.UpdatedAt = time.Now()}func (u *User) Validate(action string) map[string]string {var errorMessages = make(map[string]string)var err errorswitch strings.ToLower(action) {case "update":if u.Email