设为首页 加入收藏

TOP

理解依赖注入和控制反转(二)
2019-09-17 18:55:12 】 浏览:75
Tags:理解 依赖 注入 控制 反转
er(String name) { this.name = name; } @Override public void WriteCode() { System.out.println(this.name + " writting python code..."); } }

C# 开发人员实现Coder接口:

package DependencyInjectionDemo;

public class CSharper implements Coder {

    private String name;

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

    @Override
    public void WriteCode() {
        System.out.println(this.name + " writting c# code...");
    }
}

修改任务类中的Javaer为Coder:

public class NewTask {

    private String name;
    private Coder coder;

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

    public void SetCoder(Coder coder) {
        this.coder= coder;
    }

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

修改场景类:

package DependencyInjectionDemo;

public class DependencyInjectionDemo {

    public static void main(String[] args) {
        NewTask task = new NewTask("开发微信支付宝收款明细获取工具");
        task.SetCoder(new Javaer("张三"));
        // 都是Coder,允许注入
        // task.SetCoder(new Pythoner("李四"));
        // task.SetCoder(new CSharper("王五"));
        task.Start();
    }
}

现在,我们可以指派任务给pythoner,CSharper和Javaer了,加入以后加入了Ruby或者Go语言开发人员,类库的使用者只需要实现Coder接口,就可以把任务指派给新来的开发人员了,不需要修改NewTask代码,实现了低耦合和可扩展性。

在讲下面的内容之前,我们先来熟悉一个名词:控制反转,四个字,拆成两个词,一个是控制,一个是反转。结合上面的例子,我们的NewTask开始的时候依赖开发人员,其在内部主动创建了开发人员对象,后来我们发现这样造成了强依赖,于是就把NewTask的主动创建开发人员这个操作撤销了,修改成了在外部实现开发人员实例并传入到NewTask内部,NewTask现在只能被动的接收我们创建的开发人员对象,从主动到被动,控制实现了反转。

概念

控制反转是原则,依赖注入是方式。

除了依赖注入(Dependency Injection, 简称DI),还有另外一种方式是“依赖查找(Dependency Locate)”, 场景类需要服务类时,从一个获取点主动取得指定的服务类。这种方式变被动接收注入为主动获取,使得场景类在需要时主动获取服务类,如我们向一个统管全局的Factory传入一个字符串,Factory返回给我一个相应服务类的实例。

不过,不论使用简单工厂(Simple Factory)还是抽象工厂(Abstract Factory),都避免不了判断服务类类型或工厂类型,这样系统中总要有一个地方存在不符合OCP的if…else或switch…case结构,这种缺陷是Simple Factory和Abstract Factory以及依赖获取本身无法消除的,而在某些支持反射的语言中(如Java和C#),通过将反射机制的引入彻底解决了这个问题。

反射与依赖注入

上面的例子中,假设我们再增加一个语言的分支(如Go)而且使用了工厂模式(简单或抽象工厂),我们需要实现Coder接口,虽然符合开闭原则(对扩展开放,对修改关闭),但最终,我们还是要回到工厂方法内部,去增加一个swith或ifelse分支,以完善我们的判断,这就破坏了开闭原则。依赖注入本身是没有能力解决这个问题的,但语言本身的反射机制(Reflection)却能从根本上解决这个问题。

现在的问题是,最终我们找到的这个对象,还是需要通过“new”操作来实例化,那么,我们如何通过不修改代码的方式,“new”出一个新的实例呢?

来试着实现一下:

package DependencyInjectionDemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class DependencyInjectionDemo {

    private static String taskName; //任务
    private static String coderName; //语言
    private static String devName; //开发人员

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

        /*现在我可以把这些写到配置文件中了*/
        taskName = "新任务名称";
        coderName = "Pythoner";
        devName = "小明";

        NewTask task = new NewTask(taskName);
        Coder coder = getCoder(coderName, devName);
        task.SetCoder(coder);

        /* 以前这么写 */
        // task.SetCoder(new Pythoner("李四"));
        // task.SetCoder(new CSharper("王五"));

        task.Start();
    }

    /**
     * 根据类名获取类实例
     * @param coderName
     * @param name
     * @return 类的实例对象
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws InstantiationException
     */
    public static Coder getCo
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇java 网站源码 在线编辑模版 代码.. 下一篇动态类型序列化

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目