自制IOC容器(4)

本系列文章介绍ByxContainer的实现思路。

ByxContainer是一个简单的轻量级IOC容器,具有以下特性:

  • 使用JSON格式的配置文件
  • 支持构造函数注入、静态工厂注入、实例工厂注入、属性注入、setter注入、条件注入
  • 组件的延迟加载和单例组件
  • 根据id注册、获取容器中的组件

ByxContainer的设计借鉴了ajoo大神的博客

项目地址:github 码云

本篇文章介绍ByxContainer中的条件组件。

需求

假设现在有一个MyDao接口,以及它的两个实现类:

public interface MyDao {...}
public class MyDaoImpl1 implements MyDao {...}
public class MyDaoImpl2 implements MyDao {...}

这里还有一个MyService类,它需要使用一个MyDao,所以需要通过构造函数传进来:

public class MyService
{
    private final MyDao myDao;

    public MyService(MyDao myDao)
    {
        this.myDao = myDao;
    }
    ...
}

那么,应该如何创建一个MyService对象呢?显然,可以使用下面两种方式之一:

MyService myService = new MyService(new MyDaoImpl1());

MyService myService = new MyService(new MyDaoImpl2());

假设现在需要根据某个标志位“动态地”决定应该用哪种方式来创建MyService对象,类似下面这样:

boolean flag = ...;
MyService myService;
if (flag)
    myService = new MyService(new MyDaoImpl1());
else
    myService = new MyService(new MyDaoImpl2());

当然,这些逻辑最好不要直接写在代码里,因为这样会导致频繁修改代码和重新编译(当标志位条件改变时)。所以,我们考虑使用IOC容器来解决这个问题。

ConditionComponent实现类

根据上面的描述,可以知道,ByxContainer需要支持根据某个条件创建不同组件的功能,ConditionComponent就是用来完成这项功能的:

public class ConditionComponent implements Component
{
    private final Component predicate;
    private final Component c1;
    private final Component c2;

    public ConditionComponent(Component predicate, Component c1, Component c2)
    {
        this.predicate = predicate;
        this.c1 = c1;
        this.c2 = c2;
    }

    @Override
    public Object create()
    {
        Object p = predicate.create();
        if (p instanceof Boolean && (boolean) p) 
            return c1.create();
        return c2.create();
    }
}

public interface Component
{
    ...
    static Component condition(Component predicate, Component c1, Component c2)
    {
        return new ConditionComponent(predicate, c1, c2);
    }
}

ConditionComponent包含三个子组件:predicatec1c2,表示的逻辑是:如果predicate创建的对象为Boolean类型并且值为true,则返回c1创建的对象,否则返回c2创建的对象。

使用ConditionComponent

有了ConditionComponent,上面的需求就可以这样来实现:

Component flag = value(true);
Component myService = condition(
    flag, 
    constructor(MyService.class, constructor(MyDaoImpl1.class)),
    constructor(MyService.class, constructor(MyDaoImpl2.class))
);

或者这样:

Component flag = value(true);
Component myDao = condition(
    flag,
    constructor(MyDaoImpl1.class),
    constructor(MyDaoImpl2.class)
);
Component myService = constructor(MyService.class, myDao);

flag也可以是一个更复杂的组件定义,例如判断某个标志字符串是否是某个特定值:

Component database = value("XXX");
Component flag = instanceFactory(database, "equals", value("mysql"));
Component myDao = condition(
    flag,
    constructor(MyDaoImpl1.class),
    constructor(MyDaoImpl2.class)
);
Component myService = constructor(MyService.class, myDao);

等价于以下逻辑:

String database = "XXX";
boolean flag = database.equals("mysql");
MyDao myDao = flag ? new MyDaoImpl1() : new MyDaoImpl2();
MyService myService = new MyService(myDao);

这些配置都可以写在配置文件中,然后让ByxContainer读取配置文件来初始化容器,这样就可以在不修改代码的情况下动态改变MyService的创建过程。

原文地址:https://www.cnblogs.com/baiyuxuan/p/14403484.html