云南旅游,轻松了解 Java开发中的依靠注入(DI)和操控回转(IOC),人肉搜索

频道:今日头条 日期: 浏览:169

前语

关于这个论题, 网上有许多文章,这儿, 我期望经过最简略的言语与咱们共享.

依托注入和控制反转两个概念让许多初学这利诱, 觉得玄之又玄,不可捉摸.

这儿想先阐明两点:

  1. 依托注入和控制反转不是高档的,很初级,也很简略.
  2. 在JAVA国际,这两个概念像空气相同无所不在,完全了解很有必要.

第一节 依托注入 Dependency injection

这儿经过一个简略的事例来阐明.

在公司里有一个常见的事例: "把使命指使个程序员完结".

把这个事例用面向目标(OO)的办法来规划,一般在面向目标规划中,名词皆可规划为目标

这句话里漆黑大帝迪迦"使命","程序员"是名词,所以咱们考虑创立两个Class: Task 和 Phper (php 程序员)

Step1 规划

文件: Phper.java

package demo;
public class Phper {
private String name;
public Phper(String name){
this.name=name;
}
public void writeCode(){
System.out.println(this.name + " is wri云南旅游,轻松了解 Java开发中的依托注入(DI)和控制反转(IOC),人肉查找ting php code");
}
}

文件: Task.java

package demo;
public class Task {
private String name;
private Phper owner;
public Task(String name){
this.name =name;
this.owner = new Phper("zhang3");
}
public void start(){
S翁文凤ystem.out.println(this.name+ " started");
this.owner.writeCode();
}
}

文件: MyFramework.java, 这是个简略的测验程序.

package demo;
public class MyFramework {
public static void main(String[] args) {
Task t = new Task("Task #1");
t.start();
}
}

运转成果:

Task #1 started

hang3 is writing php code

咱们看一看这个规划有什么问题?

假如仅仅为了完结某个暂时的使命,程序即写即仍,这没有问题,只需完结使命即可.

可是假如搭档敬慕你的规划,要重用你的代码.你把程序打成一个类库(jar包)发给搭档.

现在问题来了,搭档发现这个Task 类 和 程序武极风岚舞员 zhang3 绑定在一同,他一切创立的Task云南旅游,轻松了解 Java开发中的依托注入(DI)和控制反转(IOC),人肉查找,都是程序员zhang3担任,他要把一些使命指使给Lee4, 就需求修正Task的源程序, 假如没有Task的源程序,就无法把使命指使给别人. 而一般类库(jar包)的运用者一般不需求也不该该来修正类库的源码,假如咱们都来修正类库的源码,类库就失去了重用的规划初衷.

咱们很天然的想到,应该让用户来指使使命担任人. 所以有了新的规划.

Step2 规划:

文件: Phper.java 不变.

文件: Task.java

package demo;
public class Task {
private String name;
private Phper owner;
public Task(String name){
this.name =name;
}
public void setOwner(Phper owner){
this.owner = owner;
}
public void start(){
System.out.println(this.name+ " started");
this.owner.writeCode();
}
}

文件: MyFramework.java, 这是个简略的测验程序.

package demo;
public class MyFramework {
public static void main(String[] args) {
Task t = new Task("Task #1");
P月饼歌hper owner = new Phper("lee4");
t.setOwner(owner);
t.start();
}
}

这样用户就可在运用时指云南旅游,轻松了解 Java开发中的依托注入(DI)和控制反转(IOC),人肉查找派特定的PHP程序员.

咱们知道,使命依托程序员,Task类依托Phper类,之前,Task类绑定特定的实例内裤秀,现在这种依托能够在运用时按需绑定,这便是依托注入(DI).

这个比如,咱们经过办法setOwner注入依托目标,

别的一个常见的注入办法是在Task的结构函数注入:

 public Task(String name,Phper owner){
this.name = name;
this.owner = owner;
}

在Java开发中,把一个对西伯利亚天气预报象实例传给一个新建目标的状况非常遍及,一般这便是注入依托.

Step2 的规划完结了依托注入.

咱们来看看Step2 的规划有什么问题.

假如公司是一个单纯运用PHP的公司,一切开发使命都有Phper 来完结,这样这个设就现已很好了,不必优化.

可是跟着公司的开展,有些使命需求JAVA来完结,公司招了写Javaer (java程序员),现在问题来了,这个Task类库的的运用者发现,使命只能指使给Phper,

一个很天然的需求便是Task应该即可指使给Phper也可指使给Javaer.

Step3 规划

咱们发现不论Phper 仍是 Javaer 都是Coder(程序员), 把Task类对Phper类的依托改为对Coder 的依托即可.

这个Coder能够规划为父类或接口,Phper 或 Javaer 经过承继父类或完结接口 到达归为一类的意图.

挑选父类仍是接口,主要看Coder里是否有许多共用的逻辑代码,假如是,就挑选父类

不然就选接口.

这儿咱们挑选接口的办法:

  1. 新增C动态性oder接口,
  2. 文件: Coder.java
package demo;
public interface Coder {
public void writeCode();
}
  1. 修正Phper类完结Coder接口
  2. 文件: Phper.php
package demo;
public class Phper implements Coder {
private String name;
public Phper(String name){
this.name=name;
}
public void writeCode(){
System.out.println(this.name + " is writing php code");
}
}
  1. 新类Javaer完结Coder接口
  2. 文件: Javaer.php
package demo;
public class Javaer implements Coder {
private String name;
public Javaer(String name){
this.name=name;
}
public void writeCode(){
System.out.println(this.name + " is writing ja胡丽琴va code");
}
}
  1. 修正Task由对Phper类的依托改为对Coder的依托.
  2. 文件: Task.java
package demo;
public class Task {
private String name;
private Coder owner;
public Task(String name){
this.name =name;
}
public void setOwner(Coder owner){
this.owner = owner;
}
public void start(){
System.out.println(this.name+ " started");
this单星伴月夜东升.owner.writeCode();
}罗姗姗
}
  1. 修正用于测验的类运用Coder接口:
package demo;
public class MyFramework {
public static void main云南旅游,轻松了解 Java开发中的依托注入(DI)和控制反转(IOC),人肉查找(String[] args) {
Task t = new Task("Task #1");
// Phper, Javaer 都是Cod云南旅游,轻松了解 Java开发中的依托注入(DI)和控制反转(IOC),人肉查找er,能够赋值
Coder owner = new Phper("lee4");
//Coder owner = new Javaer("Wang5");
t.setOwner(owner);
t.start();
}
}

现在用户能够和便当的把使命指使给Javaer 了,假如有新的Pythoner参加,没问题.

类库的运用者只需让Pythoner完结(implements)了Coder接口,就可把使命指使给Pythoner, 无需修正Task 源码, 前进了类库的可扩展性.

回忆一下,咱们开发的Task类,

在Step1 中与Tgai爷只认钱ask与特定实例绑定(zhang3 Phper)

在Step2 中与Task与特定类型绑定(Phper)

在Step3 中与Task与特定接口绑定(Coder)

尽管都是绑定, 从Step1,Step2 到 Step3 灵敏性可扩展性是顺次前进的.

Step1 作为反面教材不可取, 至所以否需求从Step2 提升为Step3, 要看详细状况.

假如依托的类型是仅有的Step2 就能够, 假如选项许多就选Step3规划.

依托注入(DI)完结了控制反转(IoC)的思维.

看看怎样反转的?

Step1 程序

this.owner = new Phper("zhang3");

Step1 规划中 使命Task 依托担任人owner, 就自动新建一个Phper 赋值给owner,

这儿是新建,也或许是在容器中获取一个现成的Phper,新建仍是获取,无关紧要,关键是赋值, 自动赋值. 这儿提一个赋值权的概念.

在Step2 和 Step3, Task 的 owner 是被迫赋值的.谁来赋值,Task自己不关心,或许是类库的用户,也或许是结构或容器.

Task交出赋值权, 从自动赋值到被迫赋值, 这便是控制反转.

第二节云南旅游,轻松了解 Java开发中的依托注入(DI)和控制反转(IOC),人肉查找 控制反转 Inversion of control

什么是控制反转 ?

简略的说从自动变被迫便是控制反转.

上文以依托注入的比如,对控制反转做了个简略的解说.

控制反转是一个很广泛的概念, 依托注入是控制反转的一个比如,但控制反转的比如还许多,乃至与软件开发无关.

这有点相似二八规律,人们总是用详细的实例解说二八规律,底子理沙详细的实例不等与二八规律(不了解二八规律的朋友,请轻松疏忽这个类比)

现在从其他方面谈一谈控制反转.

传统的程序开发,人们总是从main 函数开端,调用各式各样的库来完结一个程序.

这样的开发,开发者控制着整个运转进程.

而现在人们运用结构(Framework)开发,运用结构时,结构控制着整个运转进程.

比照以下的两个简略程序:

  1. 简略java程序
package demo;
public class Activity {
public Activity(){
this.onCreate();
}
public void onCreate(){
System.out.println("onCreate called");
}
public void sayHi(){
System.out.println("Hello world!");
}
public static void main(String[] args) {
Activity a = new Activity();
a.sayHi();
}
}
  1. 简略Android程序
package demo;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends Activity
{
@Override
publ性侵幼女ic void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.append("Hello ");
tv.append("world!");
setContentView(tv);
}
}

这两个程序最李杰宇大的差异便是,前者程序的运转完全由开发控制,后者程序的运转由Android结构控制.

两个程序都有个onCreate办法.

前者程序中,假如开发者觉得onCreate 称号不适宜,想改为Init,没问题,直接就能够改, 相比下,后者的onCreate 称号就不能修正.

由于,后者运用了结构,享受结构带来福利的一同,就要遵从结构的规矩.

这便是控制反转.

能够说, 控制反转是一切结构最基本的特征.

也是结构和一般类库最大的不同点.

许多Android开发工程师在享受控制反转带来的便当,去不知什么是控制反转.

就有点像深海里的鱼不知到什么是海水相同.

经过结构能够把许多共用的逻辑放到结构里,让用户专心自己程序的逻辑.

这也是为什么现在,不管手机开发,网页开发,仍是桌面程序, 也不论是Java,PHP,仍是Python结构无处不在.

回忆天辉发卡下之前的文件: MyFramework.java

package demo;
public class MyFramework {
public static void main(String[] args) {
Task t = new Task("Task #1");
Coder owner = new Phper("lee4");
t.setOwner(owner);
t.start();
}
}

这仅仅简略的测验程序,取名为MyFramework, 是由于它具有结构3个最基本特征

  1. main函数,即程序进口.
  2. 创立目标.
  3. 安装目标.(setOwner)

这儿创立了两个目标,实践结构或许会创立数千个目标,或许经过工厂类而不是直接创立,

这儿直接安装目标,实践结构或许用XML 文件描述要创立的目标和安装逻辑.

当然实践的结构还有许多这儿没触及的内容,仅仅期望经过这个简略的比如,咱们对结构有个开始知道.

控制反转还有一个美丽的比方:

好莱坞准则(Hollywood principle)

"不要打电话给咱们,咱们会打给你(假如适宜)" ("don't call us, we'll call you." )

这是好莱坞电影公司对面试者常见的答复.

事实上,不只电影职业,基本上一切公司人力资源部对面试者都这样说.

让面试者从自动联络转换为被迫等候.

为了添加本文的趣味性,这儿despire在举个比方叙述控制反转.

人们谈阜宁焦爱芹老公爱情,在曾经一般是男追女,现在年代前进了,女追男也很常见.

这也是控制反转

体会下你追女孩和女孩追你的差异:

你追女孩时,你是自动的,你是标准拟定者, 要求身高多少,颜值多少,满意你的标准,你才去追,追谁,什么时候追, 你说了算.

这就相似,结构拟定接口标准,对完结了接口的类调用.

等女孩追你时,你是被迫的,她是标准拟定者,要求有车,有房等,你买车,买房,努力工作赚钱,是为了到达标准(既完结接口标准), 你万事具备, 处于候追状况, 但时谁来追你,什么时候追,你不知道.

这便是自动和被迫的差异,也是为什么男的偏好自动的原因.

这儿仿照好莱坞准则,提一个中国帅哥准则:"不要追哥, 哥来追你(假如适宜)",

简称CGP.( Chinese gentleman principle: "don't court me, I will court you")

扩展论题

  1. 面向目标的规划思维
  2. 第一节 说到在面向目标规划中,名词皆目标,这儿做些弥补.
  3. 当面临一个项目,做体系规划时,第一个问题便是,体系里要规划哪些类?
  4. 最简略的办法便是,把要规划体系的名词提出来,一般,名词可规划为目标,
  5. 可是否一切名词都需求规划对应的类呢? 要详细问题详细分析.不是不能够,是否有必要.
  6. 有时候需求把一些动词名词化, 看看现实生活中, 写作是动词,一切写作的人叫什么? 没有适宜的称号,咱们就叫作者, 阅览是动词,阅览的人就称读者. 中文经过加"者","手"使动词名词化,舞者,歌手云南旅游,轻松了解 Java开发中的依托注入(DI)和控制反转(IOC),人肉查找,投手,射手皆是这类.
  7. 英语国际也相似,经过er, or等后缀使动词名词化, 如singer,writer,reader,actor, visitor.
  8. 现实生活这样, Java国际也相同.
  9. Java经过able,or后缀使动词名词化.如Runnable,Serializable,Parcelable Comparator,Iterator.
  10. Runnable即能够运转的东西(类) ,其他相似.
  11. 了解了动词名词化,对java里的许多类就简单了解了.
  12. 相关术语(行话)解说
  13. Java 里术语满天飞, 让初学者望而生畏. 假如你不想让许多术语影响学习,这一节可忽视.
  14. 了解了原理,叫什么并不重要. 了解些术语的优点是便于交流和阅览外文材料,还有便是让人看起来很专业的姿态.
  • 耦合(couple): 彼此绑定便是耦合第一节 Step1,Step2,Step3 都是.
  • 紧耦合(Tight coupl袁政益ing) Step1 中,Task 和 zhang3 绑在一同; Step2中 Task 和 Phper 绑在一同, 都是.
  • 松耦合(Loose coupling) Step3 中,Task 和 Coder 接口绑在一同便是
  • 解耦(Decoupling): 从Step1 , Step2, 到 Step3 的规划便是Decoupling, 让目标能够灵敏组合.
  • 上溯造型或称向上转型(Upcasting). 把一个对像赋值给自己的接口或父类变量便是.由于画类图时接口或父类在画在上面,所所以Upcasting. Step3中一下程序便是:

Coder owner = new Phper("lee4");

  • 下溯造型或称向下转型(Downcasting). 和Upcasting 相反,把Upcasting往后的目标转型为之前的目标. 这个上述程序不触及,顺带说一下

Coder owner = new Phper("lee4");

Phper p = (Phper) owner;

  • 注入(Inject): 经过办法或结构函数把一个目标传递给另一个目标. Step3 中的setOwner 便是.
  • 安装(Assemble): 和上述注入是一个意思,看个人喜爱运用.
  • 工厂(Factory): 假如一个类或目标专门担任创立(new) 目标,这个类或目标便是工厂芳飞前沿美发网
  • 容器(Container): 专门担任寄存创立好的目标的东西. 能够是个Hash表或 数组.
  • 面向接口编程(Interface based programming) Step3 的规划便是.