Go 语言的依赖注入

企鹅博客
企鹅博客
企鹅博客
28585
文章
0
评论
2020年9月15日16:54:30 评论 2 views 1476字阅读4分55秒

依赖注入(DI)是一种解耦组件之间依赖关系的设计模式。在需要的时候,不同组件之间可以通过一个统一的界面获取其它组件中的对象和状态。Go语言的接口设计,避免了很多需要使用第三方依赖注入框架的情况(比如Java,等等)。我们的注入方案只提供非常少的类似Dager或Guice中的注入方案,而专注于尽量避免手动去配置对象和组件之间的依赖关系。因为,我们认为如果在Go代码库中,注入能够更加容易理解,就根本没有必要那样。

在Go中实现注入只需要这几个简单的步骤:

全局变量

先从一个一致的、崇高的目标开始,我们需要一些如Mongo、Memcache等服务的全局连接对象。大致是这样的:

var MongoService mongo.Service
 
func InitMongoService(url string) {
  MongoService = ...
}
 
func GetApp(id uint64) *App {
  a := new(App)
  MongoService.Session().Find(..).One(a)
  return a
}

通常  main()  函数会调用配置在flags或configuration文件中如  InitMongoService  这样的各种初始化函数。这时,像 GetApp 这样的函数就可以使用这些服务和连接了。当然,有时候我们会忘记初始化全局变量,被 nil 引发panic。

虽然在创建全局变量的时候共享资源让它们(至少)有两个缺点:
首先,因为组件的依赖关系不明确,所以代码是很难写的;
其次,你很难去测试你写的代码,在并行条件下更是几乎不可能。

尽管测试是非常快的(我们希望确保一直很快),但是能够在并行环境下测试才是最重要的。使用全局连接对象时,后台服务无法在并发条件下测试出相同的数据。

 

清除全局变量

 

为了清除全局变量,我们先从一个通用模式开始。我们的组件现在显示依赖,我们将,一个Mongo服务,或者一个缓存服务。大致来讲,我们上面那个幼稚的例子现在看起来应当是这样的:

 

type AppLoader struct {
  MongoService mongo.Service
}
 
func (l *AppLoader) Get(id uint64) *App {
  a := new(App)
  l.MongoService.Session().Find(..).One(a)
  return a
}

许多引用全局变量的函数现在变成了结构体中存储了它们的依赖。

新的问题

真棒!在main()方法中,我们用一系列的构造代替了全局变量和函数,解决了我们之前遇到的问题。但是... 一看main()函数就知道了,太杂乱无章了。

一开始就这么乱了:

func main() {
  mongoURL := flag.String(...)
  mongoService := mongo.NewService(mongoURL)
  cacheService := cache.NewService(...)
  appLoader := &AppLoader{
    MongoService: mongoService,
  }
  handlerOne := &HandlerOne{
    AppLoader: appLoader,
  }
  handlerTwo := &HandlerTwo{
    AppLoader:    appLoader,
    CacheService: cacheService,
  }
  rootHandler := &RootHandler{
    HandlerOne: handlerOne,
    HandlerTwo: handlerTwo,
  }
  ...
}

继续阅读
weinxin
欢迎加入中国站长博客之家
本站的所有资源都会上传分享到博客之家,希望大家互相学习交流进步。
如何使iPad/iPhone程序满屏显示 Linux编程

如何使iPad/iPhone程序满屏显示

如何使iPad/iPhone程序满屏显示【也就是没有上面的电量条】 先上图: 有时候,我们想让我们的程序满屏,我们该怎么做呢? 步骤如下: 在工程中找到:XXX-Info.plist【其中XXX是你的...
JVM类加载机制以及类缓存问题的处理 Linux编程

JVM类加载机制以及类缓存问题的处理

当一个Java项目启动的时候,JVM会找到main方法,根据对象之间的调用来对class文件和所引用的jar包中的class文件进行加载(其步骤分为加载、验证、准备、解析、初始化、使用和卸载),方法区...
Java静态代码块使用 Linux编程

Java静态代码块使用

一、Java静态代码块与静态方法区别一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下,其他程序来调...
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: