Dagger系列(一)

Dagger系列(一)

Dagger 是一个对象注入框架,我们用采用编写接口框架自动生成实现类的方式来生成实现代码,我们只需要通过相关注解来注入对象:

举个例子,以下举例采用官方的ATM demo:

第一步加入依赖

  implementation 'com.google.dagger:dagger:2.22.1'
  annotationProcessor 'com.google.dagger:dagger-compiler:2.22.1'

第二步 创建一个CommandRouterFactory 接口

package union.com.myapplication.lesson2;
import dagger.Component;
@Component
public interface CommandRouterFactory {
    CommandRouter router();
}

@Component

这个注解是告诉dagger 实现一个接口或者是抽象类返回一个或多个对象,Dagger生成对象的名称

Dagger"yourType" 或者嵌入类(Dagger"youType"_“nestType”)

第三部 创建一个 CommandRouter 类

package union.com.myapplication.lesson2;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

public class CommandRouter {

    @Inject
    public CommandRouter() {
    }

    private final Map<String, Command> commands = Collections.emptyMap();
    Command.Status route(String input) {
        List<String> splitInput = split(input);
        if (splitInput.isEmpty()) {
            return invalidCommand(input);
        }

        String commandKey = splitInput.get(0);
        Command command = commands.get(commandKey);
        if (command == null) {
            return invalidCommand(input);
        }

        Command.Status status =
                command.handleInput(splitInput.subList(1, splitInput.size()));
        if (status == Command.Status.INVALID) {
            System.out.println(commandKey + ": invalid arguments");
        }
        return status;
    }

    private Command.Status invalidCommand(String input) {
        System.out.println(
                String.format("couldn't understand \"%s\". please try again.", input));
        return Command.Status.INVALID;
    }

    // Split on whitespace
    private static List<String> split(String string) {
        return new ArrayList<>();
    }
}

@Inject

该注解必须添加 用户告诉dagger 如何实例化一个对象

添加完成之后我们就可以rebuild 项目会自动生成实现类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PGeP3Bvo-1572332858446)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1572321927116.png)]

DaggerCommandRouterFactory 为自动生成的类:

// Generated by Dagger (https://google.github.io/dagger).
package union.com.myapplication.lesson2;

public final class DaggerCommandRouterFactory implements CommandRouterFactory {
  private DaggerCommandRouterFactory() {}

  public static Builder builder() {
    return new Builder();
  }

  public static CommandRouterFactory create() {
    return new Builder().build();
  }

  @Override
  public CommandRouter router() {
    return new CommandRouter();
  }

  public static final class Builder {
    private Builder() {}

    public CommandRouterFactory build() {
      return new DaggerCommandRouterFactory();
    }
  }
}

第四步 带参数的注入

我们编写一个HelloWorldCommand 实现Command 接口

package union.com.myapplication.lesson2;

import java.util.List;

import javax.inject.Inject;

public class HelloWorldCommand implements Command {

    @Inject
    public HelloWorldCommand() {
    }

    @Override
    public String key() {
        return "Hello";
    }

    @Override
    public Status handleInput(List<String> input) {
        if (!input.isEmpty()) {
            return Status.INVALID;
        }
        System.out.println("world!");
        return Status.HANDLED;
    }
}

修改CommandRouter 类:

package union.com.myapplication.lesson2;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

public class CommandRouter {


    private final Map<String, Command> commands = Collections.emptyMap();

    @Inject
    public CommandRouter(HelloWorldCommand command){
        commands.put(command.key(),command);
    }

    Command.Status route(String input) {
        List<String> splitInput = split(input);
        if (splitInput.isEmpty()) {
            return invalidCommand(input);
        }

        String commandKey = splitInput.get(0);
        Command command = commands.get(commandKey);
        if (command == null) {
            return invalidCommand(input);
        }

        Command.Status status =
                command.handleInput(splitInput.subList(1, splitInput.size()));
        if (status == Command.Status.INVALID) {
            System.out.println(commandKey + ": invalid arguments");
        }
        return status;
    }

    private Command.Status invalidCommand(String input) {
        System.out.println(
                String.format("couldn't understand \"%s\". please try again.", input));
        return Command.Status.INVALID;
    }

    // Split on whitespace
    private static List<String> split(String string) {
        return new ArrayList<>();
    }
}

看到没有在构造方法中添加了一个HelloWorldCommand的构造方法,同时要告诉框架怎么去创建HelloWorldCommand ,因此 HelloWorldCommand 中的构造方法中的Inject 是不能少的

看下这次dagger 框架生成的和上次生成的实现类有什么不一样的:

// Generated by Dagger (https://google.github.io/dagger).
package union.com.myapplication.lesson2;

public final class DaggerCommandRouterFactory implements CommandRouterFactory {
  private DaggerCommandRouterFactory() {}

  public static Builder builder() {
    return new Builder();
  }

  public static CommandRouterFactory create() {
    return new Builder().build();
  }

  @Override
  public CommandRouter router() {
    return new CommandRouter(new HelloWorldCommand());
  }

  public static final class Builder {
    private Builder() {}

    public CommandRouterFactory build() {
      return new DaggerCommandRouterFactory();
    }
  }
}

注意:CommandRouter 类中的构造方法需要穿具体的实现对象 那么如果要传入一个接口怎么办呢

第五步参数传递对象的接口

如果传递参数为对象的接口那么 dagger框架是无法知晓具体要实例化的对象

我们可以这样做

创建一个HelloWorldModule:

package union.com.myapplication.lesson2.module;

import dagger.Binds;
import dagger.Module;
import union.com.myapplication.lesson2.Command;
import union.com.myapplication.lesson2.HelloWorldCommand;

@Module
public abstract class HelloWorldModule {
    @Binds
    abstract Command helloWorldCommand(HelloWorldCommand command);
}

多了两个注释 @Module @Binds

这个@ Binds 方法告诉Dagger,当某些事情依赖于某个命令时,Dagger应该提供一个HelloWorldCommand对象来代替它。注意,方法的返回类型Command是Dagger现在知道如何提供的类型,而参数类型是Dagger知道在依赖于Command时使用的类型。

上面的方法之所以是抽象方法是告诉dagger 做什么,dagger并不提供该方法的实现和调用

那么 @Module 是什么东西呢

@Module 是@Binds 绑定方法的集合 必须放在 @Module 中

module 创建好了,下一步使用它

package union.com.myapplication.lesson2;
import dagger.Component;
@Component(modules = HelloWorldCommand.class)
public interface CommandRouterFactory {
    CommandRouter router();
}

我们再看看dagger 为我们生成的实现类

// Generated by Dagger (https://google.github.io/dagger).
package union.com.myapplication.lesson2;

public final class DaggerCommandRouterFactory implements CommandRouterFactory {
  private DaggerCommandRouterFactory() {}

  public static Builder builder() {
    return new Builder();
  }

  public static CommandRouterFactory create() {
    return new Builder().build();
  }

  @Override
  public CommandRouter router() {
    return new CommandRouter(new HelloWorldCommand());
  }

  public static final class Builder {
    private Builder() {}

    public CommandRouterFactory build() {
      return new DaggerCommandRouterFactory();
    }
  }
}

第六步 扩展HelloWorldCommand 中的打印方法:

定义一个 Outputter 接口

package union.com.myapplication.lesson2;

public interface Outputter {
    void output(String output);
}

修改 HelloWorldCommand:

package union.com.myapplication.lesson2;

import java.util.List;

import javax.inject.Inject;

import dagger.Module;

public class HelloWorldCommand implements Command {

    private final Outputter outputter;

    @Inject
    HelloWorldCommand(Outputter outputter) {
        this.outputter = outputter;
    }

    @Override
    public String key() {
        return "Hello";
    }

    @Override
    public Status handleInput(List<String> input) {
        if (!input.isEmpty()) {
            return Status.INVALID;
        }
        outputter.output("world!");
        return Status.HANDLED;
    }
}

OutPutter 是一个接口,我们需要提供一个实现类 然后使用Inject 来告诉dagger框怎么生成实现具体对象 然后使用 @Binds 方法绑定实现。Ok dagger 框架给我们提供了另外一种方法

@Module
abstract class SystemOutModule {
  @Provides
  static Outputter textOutputter() {
    return System.out::println;
  }
}

是不是用 Privides 注解代替了@binds 注解直接实现了方法呢

我们看下生成类:

// Generated by Dagger (https://google.github.io/dagger).
package union.com.myapplication.lesson2;

import union.com.myapplication.lesson2.module.SystemOutModule_TextOutputterFactory;

public final class DaggerCommandRouterFactory implements CommandRouterFactory {
  private DaggerCommandRouterFactory() {}

  public static Builder builder() {
    return new Builder();
  }

  public static CommandRouterFactory create() {
    return new Builder().build();
  }

  private HelloWorldCommand getHelloWorldCommand() {
    return new HelloWorldCommand(SystemOutModule_TextOutputterFactory.textOutputter());
  }

  @Override
  public CommandRouter router() {
    return new CommandRouter(getHelloWorldCommand());
  }

  public static final class Builder {
    private Builder() {}

    public CommandRouterFactory build() {
      return new DaggerCommandRouterFactory();
    }
  }
}

SystemOutModule_TextOutputterFactory 这类是不是被注入进去了?

对了忘记说了一个点:

CommandRouterFactory 不要忘记了依赖

@Component(modules = {HelloWorldModule.class, SystemOutModule.class})
public interface CommandRouterFactory {
    CommandRouter router();
}

好了这节就先到这,下次继续要不这篇内容有点多

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值