揭开均线系统的神秘面纱_揭开依赖注入的神秘面纱,并通过此快速介绍了解它的实际应用...

揭开均线系统的神秘面纱

by Sankalp Bhatia

通过Sankalp Bhatia

揭开依赖注入的神秘面纱,并通过此快速介绍了解它的实际应用 (Demystify Dependency Injection and see it in action with this quick intro)

Dependency Injection (DI) is a topic which I found a little difficult to grasp during my initial days as a software developer. I just could not find a good definition of the term.

依赖注入(DI)是一个主题,在我作为软件开发人员的最初几天,我发现它有点难以掌握。 我只是找不到一个很好的定义。

In this article, I’ve tried to put my understandings of it in fairly simple language. It is intended for people starting out with DI, or those who just want to get a little more insight.

在本文中,我试图用相当简单的语言表达对它的理解。 它适用于刚开始使用DI的人或只想获得更多见识的人。

什么是依赖注入? (What is Dependency Injection?)

First things first: what is it? Dependency Injection, like so much other software development jargon, is a fancy term for a rather simple concept.

第一件事:什么? 像其他许多软件开发术语一样,依赖注入是一个相当简单的概念的花哨术语。

The definition which I found most useful is:

我发现最有用的定义是:

Dependency injection means giving an object its instance variables.

依赖注入意味着给对象一个实例变量。

That’s it. Providing (injecting) dependencies for a class. Simple right? Indeed.

而已。 提供(注入)类的依赖关系。 简单吧? 确实。

Now, there are three ways of providing a class its dependencies in Java. All of them achieve…(coughs) Dependency Injection.

现在,有三种方法可以在Java中为类提供其依赖项。 他们都实现了……(咳嗽)依赖注入。

They are:

他们是:

  • Constructors

    建设者
  • Setters

    二传手
  • Directly setting public fields

    直接设置公共领域

让我们看看依赖注入的作用 (Let’s see Dependency Injection in action)

I have an application class named MyMessagePublisher which has a dependency on a certain EmailService class.

我有一个名为MyMessagePublisher的应用程序类,该类与某个EmailService类有关。

使用构造函数的依赖注入: (Dependency Injection using Constructor:)
public class MyMessagePublisher {    private EmailService emailService = null;        public MyMessagePublisher(EmailService emailService){        this.emailService = emailService;    }}

See what the constructor is doing there? It is telling MyMessagePublisher to use the EmailService provided by it. The class instantiating MyMessagePublisher should provide (inject) an EmailService instance (using the constructor) to be used by MyMessagePublisher. Something like this:

看看构造函数在那里做什么? 它告诉MyMessagePublisher使用它提供的EmailService。 实例化MyMessagePublisher的类应提供(注入)MyMessagePublisher要使用的EmailService实例(使用构造函数)。 像这样:

EmailService emailService = new EmailService();MyMessagePublisher myMessagePublisher =                            new MyMessagePublisher(emailService);

Good job, Constructor!

干得好,建设者!

使用Setter进行依赖注入: (Dependency Injection using Setter:)
public class MyMessagePublisher {    private EmailService emailService = null;    public MyMessagePublisher() {    }    public setEmailService(EmailService emailService) {        this.emailService = emailService;    }}

What’s going on here? The class using MyMessagePublisher can now set the EmailService which they want to use. Something like this:

这里发生了什么? 现在,使用MyMessagePublisher的类可以设置他们要使用的EmailService。 像这样:

MyMessagePublisher myMessagePublisher = new MyMessagePublisher();myMessagePublisher.setEmailService(new EmailService());

Good job, Setter!

干得好,塞特犬!

通过直接设置公共字段进行依赖注入 (Dependency Injection by directly setting public fields)

Never do this!! If you have reached this far reading this article, I believe you know that this approach is evil.

永远不要这样做! 如果您到目前为止已经阅读了本文,那么我相信您知道这种方法是邪恶的。

依赖注入的好处 (Benefits of Dependency Injection)

I’ll start this section by explaining what we miss out on if we do not use DI.

我将从解释不使用DI会错过的内容开始本节。

Consider this code. I have defined the EmailService and MyMessagePublisher classes. MyMessagePublisher itself instantiates an EmailService object instead of using the DI techniques mentioned above.

考虑一下此代码。 我已经定义了EmailService和MyMessagePublisher类。 MyMessagePublisher本身将实例化EmailService对象,而不使用上述DI技术。

public class EmailService {        public void sendEmail(String message, String receiver){        System.out.println("Email sent to " + receiver);    }}
public class MyMessagePublisher {    private EmailService emailService = new EmailService();    public void processMessages(String message, String receiver){        this.emailService.sendEmail(message, receiver);    }}

The above code has some limitations:

上面的代码有一些限制:

  1. If EmailService initialization logic changes (it takes a constructor parameter to initialize), we would need to make changes to MyMessagePublisher class along with everywhere else in the codebase where we are using EmailService without DI.

    如果EmailService的初始化逻辑发生了变化(需要使用构造函数参数进行初始化),我们将需要对MyMessagePublisher类以及我们使用无DI的EmailService的代码库中的其他所有地方进行更改。
  2. It has tight coupling. Let’s say we want to move away from sending emails and instead start sending SMSs. We will then have to write a new publisher class.

    它具有紧密的耦合。 假设我们要远离发送电子邮件,而是开始发送SMS。 然后,我们将不得不编写一个新的发布者类。
  3. This code is not testable. We will be sending emails to everyone while unit testing MyMessagePublisher class.

    此代码不可测试。 在对MyMessagePublisher类进行单元测试时,我们将向所有人发送电子邮件。

This is the solution I propose:

这是我建议的解决方案:

public class EmailService implements MessageService {    @Override    public void sendMessage(String message, String receiver) {        //logic to send email    }}
public class SMSService implements MessageService {    @Override    public void sendMessage(String message, String receiver) {        //logic to send SMS    }
public interface MessageService {    void sendMessage(String message, String receiver);}
public class MyMessagePublisher {    private MessageService messageService;        public MyMessagePublisher(MessageService messageService){        this.messageService = messageService;    }        @Override    public void processMessages(String msg, String rec){        this.service.sendMessage(msg, rec);    }}

This implementation overcomes all three limitations mentioned above.

此实现克服了上述所有三个限制。

  • EmailService (or MessageService) initialization logic moves to the module initializing MyMessagePublisher

    EmailService(或MessageService)初始化逻辑移至初始化MyMessagePublisher的模块
  • We can move to a different implementation of MessageService which sends SMS without changing code in MyMessagePublisher

    我们可以转到MessageService的其他实现,该实现发送SMS而不更改MyMessagePublisher中的代码
  • The code is testable. We can use a dummy implementation of MessageService while unit testing MyMessagePublisher

    该代码是可测试的。 在单元测试MyMessagePublisher时,我们可以使用MessageService的虚拟实现

Sweet. We have achieved DI using Constructors of our classes. Easy right? But there are some shortcomings here as well.

甜。 我们已经使用我们的类的构造函数实现了DI。 容易吧? 但是这里也有一些缺点。

香草依赖注射的问题 (Issues with Vanilla Dependency Injection)

When does this become a problem? When the code grows.

什么时候会成为问题? 当代码增长时

So what are the alternatives? Dependency Injection Containers (Spring, Guice, Dagger, and so on).

那么还有哪些选择呢? 依赖注入容器 (Spring,Guice,Dagger等)。

Let’s try to answer the questions above in more detail.

让我们尝试更详细地回答上述问题。

Consider the code below. We are designing an AllInOneApp which offers multiple services like booking movie tickets, recharging prepaid connections, transferring money, and online shopping.

考虑下面的代码。 我们正在设计一个AllInOneApp,它提供多种服务,例如预订电影票,为预付费连接充值,转账和在线购物。

public class BookingService {    private SlotsManager slotsManager;    private MyMessagePublisher myMessagePublisher; //Looks familiar?}
public class AllInOneApp  {    BookingService bookingService; // Class above    RechargeService rechargeService;    MoneyTransferService moneyTransferService;    ShoppingService shoppingService;}

AllInOneApp needs four dependencies to be initialized. Let’s use vanilla Dependency Injection using Constructor here and instantiate the AllInOneApp class.

AllInOneApp需要初始化四个依赖项。 让我们在此处使用使用构造函数的原始依赖注入,并实例化AllInOneApp类。

public static void main(String[] args) {
AllInOneApp allInOneApp = new AllInOneApp(                new BookingService(new SlotsManager(),                                   new MyMessagePublisher(                                              new EmailService())),                 new RechargeService(...),                 new MoneyTransferService(..),                new ShoppingService(...));
}

This looks messy. Can we identify the problems here? A couple of them are:

看起来很乱。 我们可以在这里找到问题吗? 其中一些是:

  • The class initializing AllInOneApp needs to know the logic to construct all the dependency classes as well. This is cumbersome when writing code in any decent sized project. Managing all these instances by ourselves is not what we want to do while writing business specific code.

    初始化AllInOneApp的类也需要知道构造所有依赖项类的逻辑。 在任何大小合适的项目中编写代码时,这很麻烦。 编写业务特定代码时,我们不想自己管理所有这些实例。
  • Although I have seen people prefer this kind of DI, I personally believe this code is less readable as compared to this:

    尽管我看到人们更喜欢这种DI,但我个人认为与以下代码相比,此代码的可读性较差:
AllInOneApp myApp = SomeDIContainer.getInstance(AllInOneApp.class);

If all the components use DI, somewhere in the system some class or factory must know what to inject into all these components (AllInOneApp, BookingService, MessageService etc).

如果所有组件都使用DI,则系统中的某个类或工厂必须知道要向所有这些组件(AllInOneApp,BookingService,MessageService等)中注入什么。

This is where Dependency Injection containers come into picture. It is called a container and not a factory because the container often takes on more responsibility than just instantiating objects and injecting dependencies.

这是Dependency Injection容器出现的地方 。 之所以称为容器而不是工厂,是因为容器通常承担的责任不仅仅是实例化对象和注入依赖关系。

DI containers let us define what components are to be initiated and what dependencies to be injected in those components. We can also configure other instantiation features, like the object being a singleton or getting created every time it is requested.

DI容器使我们可以定义要启动哪些组件以及要在这些组件中注入哪些依赖项。 我们还可以配置其他实例化功能,例如对象是单例对象,或在每次请求时创建。

I will be writing another article explaining the usage of one of the popularly used DI Containers, Google Guice, which will have a hands on practice section as well. I will update this story with it’s link soon. I will now leave you with this user guide which is a good place to start.

我将写另一篇文章,解释一种常用的DI容器Google Guice的用法,该工具还将在实践部分进行介绍。 我将通过链接更新此故事。 现在,我将为您提供本用户指南 ,这是一个很好的起点。

Thank you for reading :)

谢谢您的阅读:)

翻译自: https://www.freecodecamp.org/news/demystifying-dependency-injection-49d4b6fe6536/

揭开均线系统的神秘面纱

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值