设为首页 加入收藏

TOP

理解依赖注入和控制反转(一)
2019-09-17 18:55:12 】 浏览:71
Tags:理解 依赖 注入 控制 反转

从一个任务开始讲

某天,公司领导找到开发人员,说要开发一个微信支付宝的收款明细获取功能,我们把这个任务作为一个案例进行说明。

第一步:设计

案例精简:把任务指派给开发人员完成。本句话中,有两个名词:“任务”和“开发人员”,所以我们考虑设计两个对象(任务和开发人员)。

开发人员对象:

package DependencyInjectionDemo;

public class Javaer {
    private String name;

    public Javaer(String name) {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void WriteCode() {
        System.out.println(this.name + " writting java code...");
    }
}

任务对象:

package DependencyInjectionDemo;

public class NewTask {

    private String name;
    private Javaer javaer;

    public NewTask(String name) {
        this.name = name;
        this.javaer = new Javaer("张三");
    }

    public void Start() {
        System.out.println(this.name + " started ..");
        this.javaer.WriteCode();
    }
}

场景类:

package DependencyInjectionDemo;

public class DependencyInjectionDemo {

    public static void main(String[] args) {
        NewTask task = new NewTask("开发微信支付宝收款明细获取工具");
        task.Start();
    }
}

运行结果:

开发微信支付宝收款明细获取工具 started ..
张三 writting java code...

现在让我们来分析一下这个设计存在的问题。

  • 如果不追求复用和耦合,只是临时完成任务,这么写倒也无可厚非;
  • 如果再有别的任务指派给其他开发人员,我们需要去代码内部修改编码;
  • 如果有很仰慕你的同事需要复用你的实现,你不能打包成jar文件给他直接用,因为他不能从jar文件外部修改任务和开发人员;

Alt Text

所以,我们应当让用户来指派开发人员,改进一下:

package DependencyInjectionDemo;

public class NewTask {

    private String name;
    private Javaer javaer;

    public NewTask(String name) {
        this.name = name;
        //this.javaer = new Javaer("张三"); 删了啦
    }

    public void SetJavaer(Javaer javaer) {
        this.Javaer = javaer;
    }

    public void Start() {
        System.out.println(this.name + " started ..");
        this.javaer.WriteCode();
    }
}

场景类也要做一下修改:

package DependencyInjectionDemo;

public class DependencyInjectionDemo {

    public static void main(String[] args) {
        NewTask task = new NewTask("开发微信支付宝收款明细获取工具");
        task.SetJavaer(new Javaer("张三")); //加入这句
        task.Start();
    }
}

输出和前面的Demo是一样的:

开发微信支付宝收款明细获取工具 started ..
张三 writting java code...

现在,我们知道了一个事实,完成任务需要依赖特定的开发人员(NewTask类依赖Javaer类),开始时,NewTask类在构造时绑定开发人员,现在这种依赖可以在使用时按需要进行绑定。
这就是依赖注入

在上面的案例中,我们是通过Setter进行注入的,另外一种常用的注入方式是通过构造方法进行注入:

    public NewTask(String name, Javaer javaer) {
        this.name = name;
        this.javaer = javaer; //构造方法中进行注入
    }

这里联想一下,任务执行期间,任务执行者(本例中是张三)生病了,那么就需要另外安排一名开发人员继续任务的执行,怎么办呢?这个时候应该考虑的是Javaer这个对象的稳定性,如果开发人员这个对象稳定性非常高,我们可以考虑在NewTask的构造方法中进行注入,因为开发人员这个对象非常稳定,不会出现中途换帅的情况,但事实并非如此,张三生病了,就得允许不中断任务的情况下,重新指派另一名开发人员继续进行开发,很显然,在这个场景中,我们应该使用Setter注入,不需要重新New一个NewTask(也就是任务重新开始),直接使用Setter更换开发人员即可。

这里还有一种注入方式是配置文件注入,这就要求注入的对象稳定性非常高,甚至高到大于服务的生命周期(比如数据库连接)。

第二步:需求挖掘

我们知道,一个开发团队往往是多种开发语言并存的,有些任务适合用Java来完成,有些适合用C#,还有些任务适合用Python,现在问题来了,这个NewTask类库的使用者发现:任务只能指派给Javaer。

所以为了更好的复用,我们的需求应该变成:任务既能指派给Javaer,也能指派给Pythoner和CSharper,以及其他任何以后可能加入的开发语言。

很自然的,我想到了使用接口:

package DependencyInjectionDemo;

public interface Coder {
    void WriteCode();
}

修改原来的Javaer,实现Coder接口:

package DependencyInjectionDemo;

public class Javaer implements Coder {
    private String name;

    public Javaer(String name) {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void WriteCode() {
        System.out.println(this.name + " writting java code...");
    }
}

Python开发人员实现Coder接口:

package DependencyInjectionDemo;

public class Pythoner implements Coder{
    private String name;
    public Python
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇java 网站源码 在线编辑模版 代码.. 下一篇动态类型序列化

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目