分层选项分配继承

A hierarchical options assignment inheritance

我正在设计一个期权分配框架。

我构建了一个选项class:

public class MyOptionModule {

    public MyOptionModule() {
    }

    public void addOption(String option, String explanation) {
        //...
    }
    public void printHelp() {
        //...
    }
    public void parse(String[] args) {
        //...
    }
}

对于每个需要用户输入选项的模块,它都会有一个静态方法:

public static void assignOptions(MyOptionModule optionModule) {
    optionModule.addOption("o", "Some options");
}

在更复杂的情况下,一些模块可能包含其他模块来工作。这是一个例子:

class ReaderClass {
    public static void assignOptions(MyOptionModule optionModule) {
        optionModule.addOption("i", "Input file for reader");
    }
}

class WriterClass {
    public static void assignOptions(MyOptionModule optionModule) {
        optionModule.addOption("o", "Output file for reader");
    }
}

public class OutClass {
    public static void assignOptions(MyOptionModule optionModule) {
        optionModule.addOption("x", "Some other options in Out Class");
        optionModule.addOption("y", "Some other options in Out Class");
        optionModule.addOption("z", "Some other options in Out Class");
    }

    public static void main(String[] args) {
        MyOptionModule optionModule = new MyOptionModule();
        ReaderClass.assignOptions(optionModule);
        WriterClass.assignOptions(optionModule);
        OutClass.assignOptions(optionModule);

        if (args.length == 0) {
            optionModule.printHelp();
        }
        optionModule.parse(args);
    }
}

示例的帮助菜单:

 /*
 ======== The help menu ========
 i: Input file for reader
 o: Output file for reader
 x: Some other options in Out Class
 y: Some other options in Out Class
 z: Some other options in Out Class
 */

现在我的问题是我的程序有一些未知模块,我想调用它们的 assignOptions。

Class<? extends XXXX> toolClass = null; // Some class with assignOptions
try {
    toolClass.getMethod("assignOptions", MyOptionModule.class).invoke(null, optionModule);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
    // Exceptions, no options if NoSuchMethodException
}

虽然可以使用反射,但如果我能检查某些class是否实现了assignOptions方法,那就太好了。 assignOptions 应该是静态的,因为 class 实例与要分配的选项无关。但是,我们不能使用带有静态方法的接口来进行此类指示(已经有很多讨论)。那么有没有什么设计可以在接口获取不到静态方法的时候避免反射呢?谢谢!

除了反射或使用本机代码之外,我想不出有什么方法可以在保留您的方法的同时完成这项工作static
(在 Java 8 中你确实可以在接口中声明 static 方法,但是你不能在实现 classes 中覆盖它们。)

但是,既然你问是否有任何设计来避免这种情况,是的,有:Factories.
我想你很熟悉它们,长话短说:
您可以将 Class 及其所有静态成员转换为工厂 class 的 实例 ,然后您可以在其上使用接口。
建厂class喜欢

public class ExampleFactory
{
    public static final ExampleFactory INSTANCE = new ExampleFactory();

    private ExampleFactory(){}

    public Example newExample(){ /* ... */ }
}

可能是最接近您要求的。
您有一个额外的 class,并且您必须实例化示例 ExampleFactory.INSTANCE.newExample() 而不是 new Example(),仅此而已。

没有。您将不得不使用反射或接口和实例。

如果工具实例与选项无关,为什么不将两者分开?

OptionModule.java:

public interface OptionModule {

    void assignOptions(MyOptionsModule optionsModule);
}

MyOptionsModuleFactory.java:

public class MyOptionsModuleFactory {

    public static void createOptionsModule(Consumer<MyOptionsModule>... modules) {
        MyOptionsModule optionsModule = ...
        for(Consumer<MyOptionsModule> module : modules) {
            module.accept(optionsModule);
        }
    }
}

CustomToolModule.java:

public class CustomToolModule {
    public static class Options implements OptionsModule {
        void assignOptions(MyOptionModule optionModule) {
            ...
        }
    }


    public static void main(String[] args) {
        MyOptionsModule optionsModule = MyOptionsModuleFactory.createOptionsModule(
                new CustomToolModule.Options()
        );
    }
}

如果你使用的是Java8,你可以使用方法引用来完成类似于你想要的事情:

CustomToolModule.java:

public static class CustomToolModule {

    public static void assignOptions(MyOptionsModule optionsModule) {
        ...
    }

    public static void main(String[] args) {
        MyOptionsModule optionsModule = MyOptionsModuleFactory.createOptionsModule(
                CustomToolModule::assignOptions,
                CustomToolModule2::assignOptions
        );
        ...
    }
}