带有实现的Java“抽象类似”方法

13

以下是各个班级:

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");" 两次?

感谢回答。

CalibeR.50


1
如果每个实现都是相同的,那么为什么要抽象方法呢? - AllTooSir
你能展示一下 run() 方法是如何被调用的吗? - Guillaume Darmont
这只是一个例子,在Sub1和Sub2的运行方法中会有更多的代码。 - CalibeR.50
@Guillaume Darmont:抱歉,我还没有编写过它。只是想知道这样的事情是否可能,以便我知道如何编写它。 - CalibeR.50
1
然后你可以在超类中编写通用代码的方法,并从子类中调用它! - AllTooSir
@The New Idiot:但是这样你就不必在子类中实现它。 - CalibeR.50
6个回答

18

将共同的功能放到超类中,并定义另一个抽象方法,由子类定义自己的实现。

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”设置为私有的。在您的示例中,只能使“run”可调用吗? - CalibeR.50
2
哦,忘了 protected。我会尝试看看这是否适用于我的情况。谢谢。 - CalibeR.50
@CalibeR.50 在同一个包内,printMessage() 将是可见的... 但是在包外,只有 run() 可用。 - user000001
希望你能看到这个信息,因为它有点老了。 这种方法有一个通用名称吗?或者你甚至可以称之为设计模式吗? - Benjamin Brandmeier
1
@bdvlop:不太擅长设计模式,但在bzzzrd的回答中,他称其为“模板方法模式”。 - user000001
显示剩余2条评论

4
你可以将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");
  }
}

我编辑了我的问题,以明确我想要做什么。 - CalibeR.50
如果您选择在Sub1和Sub2中重写该方法,还需要调用super.run()。 - veritas
但是现在你可能会忘记调用super.run()。是否有可能像抽象强制覆盖方法一样强制调用它? - CalibeR.50
@CalibeR.50 不,除非你写了super.run(),否则你不能强制调用super.run()。原因是:在某些情况下,你应该完全重写一个方法,所以根本不应该调用super.run();在许多其他情况下,可能会出现需要在方法的最后调用super.run(),或者需要调用两次super.run()等情况。 - Dmitry Bychenko
3
强制子类调用超类的实现是一种代码异味。 - Jeffrey

3

使用“模板方法模式”:

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
    {

    }
}

此外,您可以使其运行受保护。

3
如果Sub1和Sub2的run()实现方式有部分相同,建议您使用继承并在子类中覆盖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并实现方法。如果有不需要共享代码的子类,您可以重写run()而无需super.run()代码,并对其进行修改。

2
您可以将常见代码放入超类方法中,并从子类方法调用它。
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
   }
}

1
是的,这个方法可以行得通。但是有没有可能强制使用“运行”来执行代码? - CalibeR.50

1
如果您希望所有子类具有相同的行为,则正确的技术是仅在超类中编写该方法,使子类可以继承它。但在这种情况下,这将消除您的超类需要抽象的必要性,因为它将实现其唯一的方法。

我会稍微编辑一下示例,以明确我想要做什么。 - CalibeR.50

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接