如何创建一个使用来自提供者的组件的组合?

时间:2014-06-22 14:08:05

标签: java design-patterns serviceloader

标题可能有点复杂,但我没有看到任何其他方式来表达我的问题。

我正在开发一个项目,通过加载多个文件并将它们转换为Java组件来初始化某些组件,其他组件由ServiceLoader加载,因为它们作为Java类存在。然后,所有这些对象都由提供者映射,以便可以从那里检索它们。

public class Provider {

    private Map<String, Component> map;

    public Provider() {
        /*
         * Load files, transform, and add them to the map 
         * with keys being their names
         */
        /*
         * Load Java components and add them to the map 
         * with keys being their names
         */
    }

    public Component getComponent(String name) {
        return this.map.get(name);
    }
}

public interface Component {
    public Number execute();
}

我现在要在Java中直接添加更多组件,但它们更像是一个复合组件,意味着它们使用先前加载到提供程序中的组件。因此,我必须从提供者那里收集所需的组件,将它们添加到组合中并将组合本身添加到提供者。

public class Composite implements Component {
    private Component component1, component2;

    public Composite() {
        Provider provider = new Provider();
        this.component1 = provider.getComponent("Comp1");
        this.component2 = provider.getComponent("Comp2");
    }

    public Number execute() {
        return this.component1.execute() + this.component2.execute();
    }
}

只需将组合添加到特定的META-INF文件即可将组合添加到提供程序。然后它将由ServiceLoader处理。

对我来说,这在某种程度上是一种循环依赖。我必须在META-INF文件中定义ServiceLoader应该收集哪些Java类。这也包括新实现的复合材料。但只要提供者已加载所有其他指标,就无法创建该文件。

我可以使用任何模式或不同的方法来解决这个问题吗?

1 个答案:

答案 0 :(得分:1)

你更有可能拥有一个链条。因此,您应该在Provider中创建一个名为Composite的接口,而不是创建CompositeComponent的新实例,该接口将扩展Component,并且还会有一个方法init(Provider provider)。或者可能更好地在代码中显示:

public interface CompositeComponent extends Component {

    void init(Provider provider);

}

然后在你的Provider

public Component getComponent(String name) {
    Component component = this.map.get(name);
    if (component instanceof CompositeComponent) {
        ((CompositeComponent)component).init(this);
    }
}