【问题标题】:A hierarchical options assignment inheritance分层选项赋值继承
【发布时间】:2015-04-30 07:30:23
【问题描述】:

我正在设计一个选项分配框架。

我已经构建了一个选项类:

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
}

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

【问题讨论】:

  • 使用java 8,你可以在接口中有静态方法;)
  • 你可以使用抽象类和声明的静态方法而不是接口吗?
  • 感谢您的想法,但我认为这不可能。因为在我的设计中,我需要让类覆盖静态方法,因为每个类都有不同的选项要分配。
  • @VeselinDavidov:Java 8 接口中的静态方法既不可覆盖,也不属于契约。 Java 8 只允许您在接口中实现静态方法。

标签: java inheritance options


【解决方案1】:

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

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

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()
        );
    }
}

如果您使用的是 Java 8,则可以使用方法引用来完成与您想要的类似的事情:

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
        );
        ...
    }
}

【讨论】:

    【解决方案2】:

    除了反射或使用本机代码之外,我想不出任何方法来使这项工作同时保持您的方法static
    (在 Java 8 中,您确实可以在接口中声明 static 方法,但您不能在实现类中覆盖它们。)

    但是,既然您问是否有任何设计来避免这种情况,是的,有:Factories
    我假设您对它们很熟悉,所以长话短说:
    您可以将 Class 及其所有静态成员转换为工厂类的instance,然后您可以在其上使用接口。
    建立一个工厂类,如

    public class ExampleFactory
    {
        public static final ExampleFactory INSTANCE = new ExampleFactory();
    
        private ExampleFactory(){}
    
        public Example newExample(){ /* ... */ }
    }
    

    可能是最接近您所要求的。
    你有一个额外的类,你必须实例化像 ExampleFactory.INSTANCE.newExample() 这样的示例而不是 new Example(),但就是这样。

    【讨论】:

      猜你喜欢
      • 2015-03-30
      • 2012-02-28
      • 1970-01-01
      • 1970-01-01
      • 2010-09-28
      • 2021-08-28
      • 2021-06-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多