【问题标题】:Java "abstract like" method with body带有主体的Java“抽象类”方法
【发布时间】:2013-07-04 14:14:58
【问题描述】:

有以下几个类:

public abstract class Super
{
    public abstract void run();
}

public class Sub1 extends Super
{
    @Override
    public void run ()
    {
        System.out.println("Method called");
        System.out.println("Sub1 called");
    }
}

public class Sub2 extends Super
{
    @Override
    public void run ()
    {
        System.out.println("Method called");
        System.out.println("Sub2 called");
    }
}

如何避免我必须编写“System.out.println("Method called");"两次?

感谢您的回答

CalibreR.50

【问题讨论】:

  • 如果每个实现都相同,那你为什么要抽象方法。
  • 你能告诉我们run()方法是如何被调用的吗?
  • 这只是一个例子,在Sub1和Sub2的run方法中会有更多的代码。
  • @Guillaume Darmont:不,抱歉,我还没有编写代码。只是想知道这样的事情是否可行,所以我知道如何编写代码
  • 那么你就可以在超类中拥有一个公共代码的方法,并从子类中调用它!

标签: java class methods abstract inheritance


【解决方案1】:

如果您希望所有子类具有相同的行为,那么正确的技术是只在超类中编写方法,允许子类继承它。但这将消除在这种情况下您的超类是抽象的需要,因为它将实现它唯一的方法。

【讨论】:

  • 我会稍微编辑一下这个例子,以明确我想要做什么
【解决方案2】:

您可以将 run() 实现放入抽象类中:

// Super is still an abstract class
public abstract class Super
{
    // While method run is not an abstract method:
    public void run() 
    {
        System.out.println("Method called");
    }
}

public class Sub1 extends Super
{
  // There's no need of declaring run() here unless you want to change its behaviour
}

public class Sub2 extends Super
{
}

在您的问题的编辑版本中,您可以只使用继承的运行实现

// Super is still abstract
public abstract class Super
{
    // But method run is not abstract
    public void run() 
    {
        System.out.println("Method called");
    }
}

public class Sub1 extends Super
{
  @Override
  public void run()
  {
      super.run(); // <- call Super.run() that prints "Method called"
      System.out.println("Sub1 called");
  }
}

public class Sub2 extends Super
{
  @Override
  public void run()
  {
      super.run();
      System.out.println("Sub2 called");
  }
}

【讨论】:

  • 我编辑了我的问题以明确我想要做什么
  • 如果您选择在 Sub1 和 Sub2 中覆盖该方法,您还需要调用 super.run()
  • 但是现在你可能会忘记调用 super.run()。是否可以像抽象强制一样强制此调用来覆盖该方法?
  • @CalibeR.50 不,您不能强制调用 super.run(),除非您编写 super.run()。原因是:在某些情况下你应该完全覆盖一个方法,所以你根本不应该调用 super.run();在许多其他情况下,您可能必须调用 super.run(),例如,在方法的最后,或者您应该调用 super.run() 两次等。
  • 强制子类调用超级实现是code smell
【解决方案3】:

您可以将公共代码放在超类方法中,并从子类方法中调用。

public abstract class Super
{
   public abstract void run();
   // code common to both the sub classes implemented
   public void print() {
     System.out.println("Method called");
   }
}

public class Sub1 extends Super
{
   @Override
   public void run ()
   {
     print();
     System.out.println("Sub1 called");
     // sub class specific code here
   }
}

public class Sub2 extends Super
{
   @Override
   public void run ()
   {
      print();
      System.out.println("Sub2 called");
      // sub class specific code here
   }
}

【讨论】:

  • 耶,这行得通。但是有没有可能强制代码用“run”来执行?
【解决方案4】:

将通用功能带入超类,并定义另一个抽象方法,子类将为其定义自己的实现。

public abstract class Super {
    public void run() {
        System.out.println("Method called");
        printMessage();
    }
    abstract void printMessage ();
}

public class Sub1 extends Super {
    @Override
    void printMessage() {
        System.out.println("Sub1 called");
    }
}

public class Sub2 extends Super {
    @Override
    void printMessage () {
        System.out.println("Sub2 called");
    }
}

这样可以避免重复调用超类的公共方法两次。

【讨论】:

  • 但我无法将“printMessage”方法设为私有。在您的示例中是否可以仅使“运行”可调用?
  • @CalibeR.50 如果它是私有的,它将无法从超类访问。但是,您可以通过省略访问级别修饰符使其包私有,并且它仅在包中可见
  • 哦,忘了受保护了。如果这适用于我的情况,我会尝试。谢谢
  • 真的不能强制执行run中的代码吗?所以不能只调用“printMessage”,而只能调用“run”?
  • @bdvlop:不太擅长设计模式,但在bzzzrd's answer 中,他称之为“模板方法模式”。
【解决方案5】:

使用“模板方法模式”:

public class Super
{
    public void template() {
        System.out.println("Method called");
        run();
    }

    public abstract void run();
}

public class Sub1 extends Super
{
    @Override
    public void run () // out called before run
    {

    }
}

public class Sub2 extends Super
{
    @Override
    public void run () // out called before run
    {

    }
}

此外,您还可以保护运行。

【讨论】:

    【解决方案6】:

    如果run() 的部分实现对于Sub1 和Sub2 都是通用的,我建议您在子类中简单地使用继承和覆盖run。下面是代码示例:

    public abstract class Super
    {
        public void run() {
            // Code shared by all subclasses
            System.out.println("Method called");
        }
    
    }
    
    public class Sub1 extends Super
    {
        @Override
        public void run ()
        {
            super.run();
            System.out.println("Sub1 called");
        }
    }
    
    public class Sub2 extends Super
    {
        @Override
        public void run ()
        {
            super.run();
            System.out.println("Sub2 called");
        }
    }
    

    这里的诀窍是Super 类可以在实现方法时定义abstract。如果您有不需要共享代码的子类,您可以覆盖没有 super.run() 代码的 run() 并全部更改。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-25
      • 2017-02-08
      • 1970-01-01
      • 2015-10-14
      • 1970-01-01
      • 1970-01-01
      • 2018-05-12
      相关资源
      最近更新 更多