【问题标题】:Inheriting the main method继承主方法
【发布时间】:2011-02-28 14:55:11
【问题描述】:

我想定义一个基类,该基类定义一个实例化该类的主方法,并运行一个方法。但是有几个问题。这是基类:

public abstract class Strategy
{
    abstract void execute(SoccerRobot robot);

    public static void main(String args)
    {
        Strategy s = new /*Not sure what to put here*/();
        s.execute(new SoccerRobot())
    }
}

这是一个派生类的例子:

public class UselessStrategy
{
    void execute(SoccerRobot robot)
    {
        System.out.println("I'm useless")
    }
}

它定义了一个简单的执行方法,当作为主应用程序使用时,它应该在主方法中调用。但是,为此,我需要从基类的 main 方法中实例化派生类。这似乎是不可能的。

我宁愿不必为每个派生类都重复 main 方法,因为这感觉有些不必要。

有正确的方法吗?

【问题讨论】:

  • 您的设计似乎有点倒退。使用特定策略实例化 SoccerRobot 不是更有意义吗?
  • SoccerRobot 代表机器人的物理属性,而不是应用程序本身。它提供对机器人的高级控制(navigateTo、getBallAngle 等)。所以我认为它不应该持有这种策略。

标签: java inheritance main-method


【解决方案1】:

您可以在子类的静态块中定义该类。

public abstract class Strategy
{
    protected static Class<? extends Strategy> instanceClass;

    abstract void execute(SoccerRobot robot);

    public static void main(String args)
    {
        Strategy s = instanceClass.newInstance()
        s.execute(new SoccerRobot())
    }
}

然后

public class UselessStrategy extends Strategy
{
    static {
        instanceClass = UselessStrategy.class;
    }

    void execute(SoccerRobot robot)
    {
        System.out.println("I'm useless")
    }
}

【讨论】:

    【解决方案2】:

    静态方法,例如“main”,不被继承,但可以直接调用。作为一种解决方法,您可以将类名参数化为 main 方法的参数:

    public static void main(String args) throws Exception
    {
      String className = (args.length > 0) ? args[0] : 'UselessStrategy';
      Strategy s = (Strategy) Class.forName(className).newInstance();
      s.execute(new SoccerRobot())
    }
    

    如果Class.forName 是不可能的,那么维护类名的映射可以提供一个查找表,根据 Andreas_D 的评论:

    private static Map<String, Class<? extends Strategy>> STRATEGY_NAME =
        new HashMap<String, Class<? extends Strategy>>();
    
    static {
        STRATEGY_NAME.put("Useless", UselessStrategy.class);
        STRATEGY_NAME.put("Better", BetterStrategy.class);
    }
    
    public static void main(String args[]) throws Exception {
        String className = (args.length > 0) ? args[0] : null;
        Class<? extends Strategy> klass = STRATEGY_NAME.get(className);
        if (klass == null) klass = UselessStrategy.class;
        Strategy s = klass.newInstance();
        s.execute();
    }
    

    如果需要,可以设计用于维护映射的自动化方法,例如使用反射。

    【讨论】:

    • Class.forName 在我的平台上是不行的。
    • Class.forName 不是必需的,还有其他方法可以将通过参数向量传递的键映射到具体类。
    • 这是像 J2ME 或 android 这样的特殊 Java 风格吗?还是有限制性的 SecurityManager?
    • 一些特殊的 java 风格。 LeJOS NXJ,确切地说。
    • 嗯,你应该把这个名字放在问题中,也许是一个标签;它似乎是一个专门的 Java 实现。
    【解决方案3】:

    我会重新考虑。

    将您想要执行的代码放在其他地方,最好是非静态方法,然后调用它。 main() 不应该这样使用。

    我建议创建一个单独的 Strategy 类来代替 main。

    【讨论】:

      【解决方案4】:

      main 方法是从哪里调用的?如果它需要参数,那么您可以根据这些参数决定具体的策略,实例化该策略类并在其上调用 execute 方法。

      【讨论】:

      • 程序执行时调用main方法。 UselessStrategy 类将被编译,这将 希望 调用 Strategy 中的 main 方法
      【解决方案5】:

      将 main 方法移出到一个单独的类中。分离关注点
      策略(名字说明了一切)
      启动器(将组件组装在一起并触发执行)

      public class Launcher
      {
          public static void main(String args)
          {
             Strategy s = new UselessStrategy();
                //OR Strategy s = CreateInstance(args[0]) ;
                //OR equiv mechanism for Dependency Injection if you don't want to hardcode the derived strategy to use.
              s.execute(new SoccerRobot())
          }
      }
      

      【讨论】:

        【解决方案6】:

        你不能实例化一个抽象类,但你绝对可以从基类实例化一个派生类。所以只需从类定义中删除抽象

        public class UselessStrategy
        

        然后做

        Strategy s = new UselessStrategy();
        

        【讨论】:

        • 第一个错误是复制粘贴。如果我要从 Strategy 派生另一个类,比如Useful Strategy,我希望基类的主要方法能够工作。我希望 main 方法以某种方式知道它是从哪个类调用的,并实例化该类。
        • 基类的主方法对任何派生类都不起作用,只对它自己起作用,就像任何其他静态方法一样。但是由于人们已经发明了命令行参数,因此在您的情况下实际上不需要多个主要方法。使用参数作为工厂的输入来创建您的策略。
        猜你喜欢
        • 1970-01-01
        • 2016-09-01
        • 2012-04-25
        • 2011-03-03
        • 1970-01-01
        • 1970-01-01
        • 2021-08-22
        • 2011-10-05
        • 2014-10-04
        相关资源
        最近更新 更多