系统设计:你的service要用Dependency Injection吗?

简介: 系统设计:你的service要用Dependency Injection吗?

正文


我最近在给一个Go service升级重构framework。我和一个朋友提了下,他点评到,搞这种基础升级,就是悟道啊,类似于《禅与摩托车维修艺术》。


image.png


他这个说法挺有道理的,大家平时写业务代码,更多是站在地面想着怎么快速完成目标。只有趁升级的时候,才有空飞在1000公里天上,想想为啥要这么设计的哲学问题。


今天就给大家介绍一个重要的基本设计原则:Dependency Injection。这个设计模式在复杂的业务service非常有用,没有它,每次改一个模块的初始化接口,你都要把用到这个模块的代码都改一遍,非常麻烦。


今天很多主流的开源framework都用到了它,比如:


  • Guice: Google 维护的一个基于Java的 lightweight dependency injection framework
  • Fx: Uber 维护的一个基于Go的dependency injection framework
  • AngularJS: Google 维护的基于JavaScript的前端 framework
  • Wire: Google维护的Compile-time Dependency Injection for Go


什么是Dependency Injection?


这个翻译成中文叫做依赖注入,用大白话解释就是即插即用。


举个例子,假设你的service里面有个模块A叫“笔记本”,它有个依赖叫“耳机”,用了这个设计原则,你需要听音乐,只用插”耳机“就可以了。后端service中常见的“耳机”依赖有哪些?比如Logging,输出Metrics等。


image.png

下面的代码是用 Dependency Injection 创建模块A的伪代码:


func CreateLaptopService() *LaptopService {
  panic(wire.Build(
    wire.Struct(new(Logger), "*"),
    NewHttpClient,
    NewHeadphoneService,
  ))
}


不用这个原则,有什么后果?


你需要自己搞一堆耳机的原材料,然后自己组装配置。模块A需要耳机的时候,手动装一遍,模块B需要耳机的时候,再手动装一遍。


image.png

下面是不用Dependency Injection,创建模块A的伪代码:


func CreateLaptopService() *LaptopService {
  logger := &Logger{}
  headphone := &Headphone{}
  client := NewHttpClient(logger)
  return NewLaptopService(logger,client,headphone)
}


如果service很简单,还可以忍受。但是在业务很复杂时,项目里有上百个依赖的时候就更痛苦了。每次配置”耳机“,你都需要手动把所有模块的接口配置一遍。


下面是不用Dependency Injection,再创建模块B的伪代码:


func CreateDesktopService() *DesktopService {
  logger := &Logger{}
  headphone := &Headphone{}
  client := NewHttpClient(logger)
  cdDisk := &CdDisk{}
  cdDrive := &CdDrive{cdDisk}
  headphone := &Headphone{}
  return NewLaptopService(logger, client, headphone, cdDrive)
}


优点一:减少依赖关系、方便重复使用


有了Dependency Injection,每次配置时,模块A和模块B都是连接到同一个设置的耳机,你只要组装一次耳机。即使有100个模块都需要用耳机,你也只需要组装一次。


image.png


优点二:提高可维护性


而对于更复杂的场景,模块B依赖于一个”CD机“,而”CD机“又需要一个”CD碟片“。如果有100个类似的模块都有”CD机“,而你需要做的只是更改”CD机”里的CD碟片,有了Dependency Injection,你也可以省去在“电子厂”里面翻找所有”CD机“的时间,只需要换一张”CD碟片“。


优点三:简化测试流程


每次升级时,只需要测试”耳机“本身的性能,测试不需要和使用”耳机“的代码有任何关联。


总结


最后,划一下重点,Dependency Injection适用的场景,是复杂的大型系统,有很多个服务相互依赖的情况。它能够避免一些重复劳动带来的小错误,提高生产力。如果是一个人写的小玩具,那杀鸡就不用牛刀啦。

相关文章
|
3天前
|
前端开发 Java 开发者
深入理解Spring Boot中的@Service注解
【4月更文挑战第22天】在 Spring Boot 应用开发中,@Service 注解扮演着特定的角色,主要用于标识服务层组件。本篇技术博客将全面探讨 @Service 注解的概念,并提供实际的应用示例,帮助开发者理解如何有效地使用这一注解来优化应用的服务层架构
97 1
|
6月前
|
Java Spring
Spring Boot使用策略模式指定Service实现类
Spring Boot使用策略模式指定Service实现类
|
3天前
|
前端开发 Java Spring
使用Spring Boot集成Shiro时出现了无法注入Service的问题
使用Spring Boot集成Shiro时出现了无法注入Service的问题
|
12月前
|
Java Linux Spring
每日一博 - Spring Boot Application as a Service
每日一博 - Spring Boot Application as a Service
74 0
|
存储 缓存 安全
Spring Security系列教程11--Spring Security核心API讲解
前言 经过前面几个章节的学习,一一哥 带大家实现了基于内存和数据库模型的认证与授权,尤其是基于自定义的数据库模型更是可以帮助我们进行灵活开发。但是前面章节的内容,属于让我们达到了 "会用" 的层级,但是 "为什么这么用",很多小伙伴就会一脸懵逼了。对于技术学习来说,我们追求的不仅要 "知其然",更要 "知其所以然"! 本篇文章中,壹哥 就跟各位小伙伴一起来了解剖析Spring Security源码内部,实现认证授权的具体过程及底层原理。接下来请各位做好心理准备,以下的学习过程可能会让你心理 “稍有不适” 哦,因为每次看源码都懵懵的...... 一. Spring Security认证请求完整
334 0
|
存储 安全 算法
Spring security (一)架构框架-Component、Service、Filter分析
  想要深入spring security的authentication (身份验证)和access-control(访问权限控制)工作流程,必须清楚spring security的主要技术点包括关键接口、类以及抽象类如何协同工作进行authentication 和access-control的实现。
298 0
|
JavaScript Java Linux
在Pivotal Web Service上发布Spring Boot应用
在Pivotal Web Service上发布Spring Boot应用
180 0
在Pivotal Web Service上发布Spring Boot应用
|
前端开发 Java Android开发
ABAP模拟Java Spring依赖注入(Dependency injection)的一个尝试
ABAP模拟Java Spring依赖注入(Dependency injection)的一个尝试
ABAP模拟Java Spring依赖注入(Dependency injection)的一个尝试
|
Java Maven Spring
spring cloud架构 - HongHu common-service 项目构建过程
spring cloud架构 - HongHu common-service 项目构建过程 Maven(项目构建)、Spring Boot、Spring Cloud、微服务概念、去中心化思想、分布式等,针对于common-service的顶级项目,这里我们主要使用Maven来构建,闲话少说,我们直接上代码是最直观的。
1333 0