是否可以使用在其父类(内部类)中实现的类?

时间:2014-07-31 17:34:06

标签: java namespaces inner-classes

让我们考虑一个简单的类Action,它意味着遍历多个阶段,一个预先定义的状态顺序,直到到达最后一个阶段。这些阶段应该由公共类Stage的子类表示,并封装在调用方法Action时要执行的proceed()类的代码。此方法也返回下一阶段。

我希望这是一个合理的设计,因为我认为它比具有状态常量的枚举和带有switch-case的proceed()更清晰。

它可以简单地用内部类实现:

public class Action {

    private int m;
    private Stage stage;

    public Action() {
        stage = new FirstStage();
    }

    public void proceed() {
        if (stage != null) {
            stage = stage.proceed();
        }
    }

    public interface Stage {

        /**
         * Executes current stage and returns next stage.
         *
         * @return
         */
        Stage proceed();
    }

    public class FirstStage implements Stage {

        @Override
        public Stage proceed() {
            m = 100;
            return new SecondStage();
        }

    }

    public class SecondStage implements Stage {

        @Override
        public Stage proceed() {
            //do something
            return null; // last stage
        }

    }
}

但我对Stage类中松散地驻留的所有Action子类感到恼火,尽管它们属于一起。要解决这个问题并获得方便的命名空间,将阶段类实现为Stage的内部类会很有用。所以我们会写Stage.First而不是FirstStage我认为更清楚。

public class ActionB {

    private int m;
    private Stage stage;

    public ActionB() {
        stage = new Stage.First(); // error
    }

    public void proceed() {
        if (stage != null) {
            stage = stage.proceed();
        }
    }

    public abstract class Stage {

        /**
         * Executes current stage and returns next stage.
         *
         * @return
         */
        public abstract Stage proceed();

        public class First extends Stage {

            @Override
            public Stage proceed() {
                m = 100;
                return new Second();
            }

        }

        public class Second extends Stage {

            @Override
            public Stage proceed() {
                //do something
                return null; // last stage
            }

        }
    }
}

我必须改变的第一件事是使Stage成为一个抽象类,因为接口是静态的,因此无法访问Action的成员。

现在的问题是实例化构造函数中的第一个阶段。 编译器错误:

  

错误:需要包含ActionB.Stage.First的封闭实例

当然我明白内部类需要一个外部类的实例。但是如果外部类是抽象的甚至是静态的(接口)呢?这不应该起作用吗?

还有办法实现嵌套吗?或者这是不好的设计?

2 个答案:

答案 0 :(得分:2)

您不需要将switch语句与enum一起使用。您也可以使用干净的继承概念:

public class Action {
    private int m;
    private Stage stage;

    public Action() {
        stage = Stage.FIRST;
    }
    public void proceed() {
        if (stage != null) {
            stage = stage.proceed(this);
        }
    }

    enum Stage {
      FIRST {
        @Override
        Stage proceed(Action a) {
          a.m = 100;
          return SECOND;
        }
      },
      SECOND {
        @Override
        Stage proceed(Action a) {
          //do something
          return null; // last stage
        }
      }
      ;
      /**
       * Executes current stage and returns next stage.
       */
      abstract Stage proceed(Action a);
    }
}

尝试嵌套类的问题是无法解决的:当将abstractStage的所有子类声明为非static内部类时,这些类需要外部实例在施工时Stage。但是,没有用作外部实例的实例,因为Stageabstract,并且所有子类都是需要已经存在的实例的内部类,因此会产生鸡与蛋的问题。

正如您已经发现的那样,您无法声明内部类static,因为Stage是非static而Java不允许static成员使用非static 1}}内部类,但无论如何内部类都是static它们没有外部Action实例也无济于事,这就是你的尝试。否则,您可以通过引入参数来使用上面的解决方案,该解决方案已经处理了内部enum始终为static的事实。

因此,预期的类名空间嵌套仅适用于static内部类,这不适合使用隐式外部实例的想法:

public class ActionB {

  private int m;
  private Stage stage;

  public ActionB() {
      stage = new Implementations.First(this);
  }
  public void proceed() {
      if (stage != null) {
          stage = stage.proceed();
      }
  }

  public abstract class Stage {
    public abstract Stage proceed();
    ActionB outer() { return ActionB.this; }
  }
  static class Implementations {

      public static class First extends Stage {
          First(ActionB outer) { outer.super(); }

          @Override
          public Stage proceed() {
              outer().m = 100;
              return new Second(outer());
          }
      }

      public static class Second extends Stage {
          Second(ActionB outer) { outer.super(); }

          @Override
          public Stage proceed() {
              //do something
              return null; // last stage
          }
      }
  }
}

如果你走得那么远,最好将我的第一个建议的解决方案与提供所需的无法方法的前端类一起使用:

public class Action {

  private int m;
  private Stage stage;

  public Action() {
      stage = new Stage(StageImpl.FIRST);
  }
  public void proceed() {
      if (stage != null) {
          stage = stage.proceed();
      }
  }

  public class Stage {
    final StageImpl stage;
    Stage(StageImpl next) {
      stage=next;
    }
    public Stage proceed() {
      StageImpl next=stage.proceed(Action.this);
      return next==null? null: new Stage(next);
    }
  }
  enum StageImpl {
    FIRST {
      @Override
      StageImpl proceed(Action a) {
        a.m = 100;
        return SECOND;
      }
    },
    SECOND {
      @Override
      StageImpl proceed(Action a) {
        //do something
        return null; // last stage
      }
    }
    ;
    abstract StageImpl proceed(Action a);
  }
}

所以你已经在某种名称空间(StageImpl)中对实现进行了封锁,并且有一个前端类Stage,它为预期的proceed()方法提供了不变的语义。

答案 1 :(得分:0)

您可以创建局部变量,每个变量都是Stage实现。因此,您没有内部类(已命名),并且此代码有效。 就个人而言,我认为你有简单的动作引擎,并会区分框架和实现。例如,proceed()方法我应该移动一个ActionRunner类。

public class Action
{
   private int m;
   private Stage stage;
   private Stage stage1=new Stage() {

       @Override
       public Stage proceed() {
           m = 100;
           return stage2;
       }
   };

   private Stage stage2=new Stage() {

       @Override
       public Stage proceed() {
           //do something
           return null; // last stage
       }
   };

    public Action() {
        stage = stage1;
    }

    public void proceed() {
        if (stage != null) {
            stage = stage.proceed();
        }
    }

    public interface Stage {
        /**
         * Executes current stage and returns next stage.
         *
         * @return
         */
        public abstract Stage proceed();
    }

}

我首先尝试使Stage实现静态但是他们无法访问Action类变量。