依赖注入–手动方式

依赖注入是一种将行为与依赖解决方案分开的技术。 用简单的话来说,它允许开发人员定义具有特定功能的类,这些功能取决于各种协作者,而不必定义如何获取对这些协作者的引用。 以此方式,实现了各个组件之间的解耦,并且通常引入了更简洁的代码。 更具体地说,一个组件仅列出必要的服务,而不是对依赖项进行硬编码,而在运行时,一个外部独立的组件将提供对这些服务的访问。 我们不应忘记,依赖注入只是控制反转的一种特殊形式,其中关注点的反转是获取所需依赖关系的过程。 前述技术的参考文章是Martin Fowler的 “控制容器的倒置和依赖注入模式” 。

为了注入依赖关系,已经出现了许多框架,最著名的是Spring和Guice (请参阅JavaCodeGeeks Spring相关文章)。 但是,对于小型项目使用整个框架无疑是一个过大的杀伤力。 我们的JCG合作伙伴之一, “按代码死亡”博客的作者,撰写了有关如何手动处理依赖项注入的小介绍。 让我们看看他怎么说?

在另一篇文章中, “我真的需要单身人士吗?” ,我写了有关Singleton设计模式引入的问题的文章。 通过getInstance()方法访问单个唯一实例时,Singleton会变相充当全局变量,并引入紧密耦合和不必要的依赖关系。 我收到了读者的两个直接问题:

单例应该仅与依赖注入框架一起使用吗?
如果通过getInstance()访问Singleton创建紧密耦合,则通过new()创建任何其他类的实例也将导致紧密耦合。 那么,如何创建一个保持松散耦合的对象?

根据我的理解,依赖注入是这两个问题的答案。 但是,这并不要求使用框架。 依赖注入首先是一个概念,然后是一个框架。 当所讨论的应用程序很小时,我们总是可以通过手动注入依赖项来满足需求,而无需使用诸如Spring之类的框架。

在任何Java应用程序中,我们都会反复遇到两个事件:

  • 对象创建
  • 对象之间的交互–业务逻辑

但是,通常我们将两者混为一谈,从而导致紧密耦合和不必要的依赖关系,这反过来又使维护以及单元测试变得痛苦。 让我尝试使用一个非常简单的示例来解释它:

class MyClass {private A a; //A is an interfaceprivate B b; //B is an interface//Object creation within constructorMyClass(A a, B b) {  a = new AImpl(); //AImpl is the concrete impl of Ab = new BImpl(); //BImpl is the concrete impl of B}//Application logic lies within this methodpublic void doSomething() {//Do A specific thing//Do B specific thingC c = new CImpl(); //Object creation within the method.//Do C specific thing}
}

此类的问题是:

  1. 它无法将对象创建与业务逻辑分开,从而导致紧密耦合。
  2. 这里已经完成了“实现编程”,而不是接口。 明天,如果需要A,B或C的不同实现,则必须更改类中的代码。
  3. 测试MyClass需要首先测试A,B,C。

让我尝试解决问题:

class MyClass {private A a;private B b;private C c;MyClass(A a, B b, C c) {//Only Assignmentthis.a = a;this.b = b;this.c = c;}//Application Logicpublic void doSomething() {//Do A specific thing//Do B specific thing//Do C specific thing}
}//The Factory
class MyFactory {public MyClass createMyClass() {return new MyClass(new AImpl(), new BImpl(), new CImpl());}
}class Main {public static void main(String args[]) {MyClass mc = new MyFactory().createMyClass();mc.doSomething();}
}

在这里已经实现了什么:

1.构造函数没有new():
没有在MyClass的构造函数中创建对象。 构造函数仅用于字段(A,B,C)分配。 在这里,构造函数要求依赖项作为参数,但不创建它们(这是依赖项注入的最简单定义)。 但是,可以在构造函数内创建简单的Collection对象(如ArrayList,HashMap或value / leaf对象,如Person / Employee)(即应用程序内的对象,这些对象又不会创建其他对象)。 构造函数不得用于任何其他操作,例如I / O,线程创建等。

根据经验法则,任何对象都应仅保留对其直接完成工作所需的其他对象的引用(这称为Demeter法则)。 例如,如果MyClass需要其他名为X的类,则MyClass的构造函数应直接要求X。不应要求其他工厂F可以返回X的实例。违反“ De​​meter法则”将导致不必要的依赖性因此,如果您发现多个Dot(。)运算符,请当心-那里发生了非法事件。

2. Factory(MyFactory)负责对象的创建和连接:
所有新的操作员(90%-99%)应属于工厂。 它应负责为应用程序创建整个对象图,并应根据声明的依赖关系关联(连接)不同的对象(例如,MyClass需要A,B,C等)。 它不应包含任何其他内容-不应包含任何其他逻辑(没有I / O,线程创建等)。

明天如果C开始依赖于其他称为D的东西,则只会影响C和工厂,而不会影响整个对象图(C必须引入重载的构造函数,并且工厂必须合并对象实例化以及与对象接线相关的更改) 。

对于大型应用程序,当然可能会有多个工厂。 在这里,经验法则是一个工厂应该实例化具有相同寿命的所有对象。

3.对象的创建与业务逻辑是分开的:
MyClass现在是业务逻辑持有人。 它没有任何new()。 甚至,它也不了解用于业务逻辑的具体实现(即,它了解A,但不了解AImpl,即“接口程序而不是实现程序”)。

您一定已经开始认为我是在Singleton的背景下开始讨论的。 手动依赖项注入如何处理Singleton? 如何创建一个Singleton(减去紧密耦合,隐藏的依赖关系等)并在需要时访问它? 令人惊讶的是,我们的示例中已经包含三个Singleton-AImpl,BImpl,CImpl。 如果工厂只负责创建Class的一个实例(通过仅调用new()一次),则其为Singleton。 是不是 然后,工厂可以将该依赖关系形式的唯一实例传递给需要它的所有其他对象。

4.那么,我们在哪里?
业务逻辑持有者MyClass的业务需要A,B和C。 它不会创建它们,而是要它们(依赖项)。 工厂(MyFactory)创建这些依赖关系并将其关联到MyClass。 但是,谁创造了工厂? 当然是主要方法(应用程序启动器:-)。 让我再重复一遍这个故事:main方法首先实例化工厂,工厂反过来实例化对象图,每个Object声明其依赖关系,最后main方法本身设置滚动-通过调用MyClass的doSomething()启动应用程序,即。 这些对象开始互相交谈,执行日常业务。

让我再重复一次: 创建工厂,使用工厂创建应用程序,然后启动应用程序! 对于大规模应用程序,可以通过像Spring,Google Guice等依赖注入框架来实现相同的目的。当然,它们还将带来许多其他好处。 但是,对于中小型应用程序,可以手动制作依赖项注入,从而使应用程序松散耦合,更易于维护,并且当然可以进行单元测试。

相关文章 :
  • 使用Spring AspectJ和Maven进行面向方面的编程
  • JBoss 4.2.x Spring 3 JPA Hibernate教程
  • GWT Spring和Hibernate进入数据网格世界
  • 建立自己的GWT Spring Maven原型
  • GWT 2 Spring 3 JPA 2 Hibernate 3.5教程– Eclipse和Maven 2展示
  • 使用Spring使用Java发送电子邮件– GMail SMTP服务器示例

翻译自: https://www.javacodegeeks.com/2010/12/dependency-injection-manual-way.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/374684.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一个疏忽引发的思考!(strerror)

前几天写代码因为自己的疏忽导致一遍又一遍的Segmentation fault (core dumped)。该问题是因为strerror(errno)返回的指针指向非法的内存导致程序打印错误时崩溃。 尝试数次无果,为了进度。简单粗暴的换成了perror(str)。今天忙里偷闲&#x…

力扣面试题 01.08. 零矩阵

编写一种算法,若M N矩阵中某个元素为0,则将其所在的行与列清零 代码一思路: 第一次遍历时记录,用两个布尔类型数组标记行和列中是否有0元素; 第二次遍历时置零 class Solution {public void setZeroes(int[][] matr…

Java最佳实践–字符串性能和精确字符串匹配

在使用Java编程语言时,我们将继续讨论与建议的实践有关的系列文章,我们将讨论String性能调优。 我们将专注于如何有效地处理字符串创建, 字符串更改和字符串匹配操作。 此外,我们将提供我们自己的用于精确字符串匹配的最常用算法的…

mac下开发环境常用操作与命令

【1】 修改hosts文件 vim /private/etc/hosts转载于:https://www.cnblogs.com/zsmynl/p/4714492.html

keil里面填数据

编译后寄存器和堆栈的内存数据可以直接写进去的。 寄存器,双击就可以,注意里面是十六进制 堆栈,也是十六进制,八位的 00 00 00 00 ,但这个是从右到左的,比如0x00000006 应该填 06 00 00 00 把数据取出来 取…

力扣498. 对角线遍历

给你一个大小为 m x n 的矩阵 mat ,请以对角线遍历的顺序,用一个数组返回这个矩阵中的所有元素。 代码思路:以第一行和右边最后一列作为每轮的开始元素,先用temp存储,全部按 从左上到右下 的顺序遍历,但是…

调试生产服务器– Eclipse和JBoss展示

您是否编写有错误的代码? 不,当然不。 对于我们其余的确实会编写带有错误的代码的凡人,我想解决一个非常敏感的问题:调试在生产服务器上运行的应用程序。 因此,您的应用程序已准备好进行部署。 单元测试全部成功&…

ubuntu server获取并自动设置最快镜像的方法

一,安装方法1 add-apt-repository ppa:ossug-hychen/getfastmirrorapt-get install getfastmirror 如果添加了临时源,这样移除add-apt-repository --remove ppa:ossug-hychen/getfastmirror 二,安装方法2 wget -O getfastmirror-master.zip h…

linux之x86裁剪移植---ffmpeg的H264解码显示(420、422)

在虚拟机上yuv420可以正常显示 ,而945(D525)模块上却无法显示 ,后来验证了directdraw的yuv420也无法显示 ,由此怀疑显卡不支持 ,后把420转换为422显示。420显示如下:/* 编译命令:arm…

Spring依赖注入技术的发展

回顾Spring框架的历史,您会发现实现依赖注入的方式在每个发行版中都在增加。 如果您使用该框架已经超过一个月,那么在这篇回顾性文章中可能不会发现任何有趣的东西。 除了Scala中的最后一个示例,没有其他希望,这种语言在Spring中意…

JS encode decode

网上查到的全都是escape,和需要的编码不是一回事,好不容易找到的结果 保存下来以备以后使用js对文字进行编码涉及3个函数:escape,encodeURI,encodeURIComponent,相应3个解码函数:unescape,decodeURI,decodeURIComponen…

流媒体服务器 笔记

1.sip服务器回SBC Port Unreachable 说明转码器接收RTCP的端口没有打开 转载于:https://www.cnblogs.com/luoyinjie/p/7219359.html

力扣151. 翻转字符串里的单词

给你一个字符串 s ,逐个翻转字符串中的所有 单词 。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 请你返回一个翻转 s 中单词顺序并用单个空格相连的字符串。 没思路,看到的官方给的,简洁明了&…

Spring 3 HornetQ 2.1集成教程

通过Spring框架使用JBoss的新超高性能消息传递系统。 HornetQ是一个开放源代码项目,用于构建多协议,可嵌入,非常高性能的集群异步消息传递系统。 它是用Java编写的,并且可以在具有Java 5或更高版本运行时的任何平台上运行。 Horn…

B/S和C/S架构图解

软件:B/S和C/S两种架构模式。接下来用三张图片解释,什么是B/S什么是C/S。 图片一:软件架构模式 图片二:C/S结构模式 图片三:B/S结构模式 相信图解胜过冗长文字的解释,什么是B/S什么是C/S一目了然。 转载于:…

557. 反转字符串中的单词 III

给定一个字符串&#xff0c;你需要反转字符串中每个单词的字符顺序&#xff0c;同时仍保留空格和单词的初始顺序。 class Solution {public String reverseWords(String s) {StringBuffer res new StringBuffer();int length s.length();int i 0;while(i < length){int …

休眠陷阱

我已经使用Hibernate已有一段时间了&#xff0c;当我一段时间不使用Hibernate项目时&#xff0c;发现自己犯的错误与上次相同。 因此&#xff0c;这是我的监视清单&#xff0c;希望对其他人也有用。 实现hashCode和equals 一般而言&#xff0c;应该始终实现这些方法&#xff…

HDU 5371 Hotaru's problem (Manacher,回文串)

题意&#xff1a;给一个序列&#xff0c;找出1个连续子序列&#xff0c;将其平分成前&#xff0c;中&#xff0c;后等长的3段子序列&#xff0c;要求【前】和【中】是回文&#xff0c;【中】和【后】是回文。求3段最长为多少&#xff1f;由于平分的关系&#xff0c;所以答案应该…

bash 与 dash

Ubuntu 的 bash和dash的区别 什么是bash &#xff1f; Bash(GNU Bourne-Again Shell)是许多Linux平台的内定Shell&#xff0c;事实上&#xff0c;还有许多传统UNIX上用的Shell&#xff0c;像tcsh、csh、ash、bsh、ksh等 等&#xff0c;Shell Script大致都类同&#xff0c;当您学…

350. 两个数组的交集 II

给你两个整数数组 nums1 和 nums2 &#xff0c;请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数&#xff0c;应与元素在两个数组中都出现的次数一致&#xff08;如果出现次数不一致&#xff0c;则考虑取较小值&#xff09;。可以不考虑输出结果的顺序。 来源&a…