Java 接口:在实现类中使用默认方法实现

时间:2021-01-13 10:40:02

标签: java oop design-patterns

我有一个接口和它的 2 个或多个实现说,

public interface IProcessor {
  default void method1() {
   //logic
  }
  default void method2() {
   //logic
  }
  public void method3();
  public void method4();
}

此处,method1method2 实现逻辑在所有多个多个实现类中是通用的。所以定义为默认方法。所以只有其余的方法可以在实现类中被覆盖。

public CarImpl implements IProcessor {
  @Override 
  public void method3() {
    //logic
  }
  @Override 
  public void method4() {
    //logic
  }
}

public VanImpl implements IProcessor {
  @Override 
  public void method3() {
    //logic
  }
  @Override 
  public void method4() {
    //logic
  }
}

是否有更好的方法可以在没有默认方法和相应实现类中的冗余代码的情况下实现这一点?因为如果 default 方法中的代码增加,则界面看起来很笨拙。

2 个答案:

答案 0 :(得分:3)

可以覆盖默认方法

你说:

<块引用>

所以只有其余的方法可以在实现类中被覆盖。

那里的“只有”这个词是错误的。接口中的默认方法确实可以被实现类覆盖。因此,此处将单词 default 用作关键字,意思是:如果在运行时没有其他实现代码,则使用此方法代码。

这是一个愚蠢的人为例子,我们定义了一个接口 Fruit,默认方法 isJuicy 返回 true。我们有两个子类,OrangeBanana。第一个没有覆盖 isJuicy,所以它的行为来自默认方法。第二个说明您可以覆盖默认方法。在这里,我们看到了覆盖返回 false

package work.basil.example;

public class OverridingDefault
{
    public static void main ( String[] args )
    {
        OverridingDefault app = new OverridingDefault();
        app.demo();
    }

    private void demo ( )
    {
        System.out.println( "new Orange().isJuicy(): " + new Orange().isJuicy() );
        System.out.println( "new Banana().isJuicy(): " + new Banana().isJuicy() );
    }

    public interface Fruit
    {
        default boolean isJuicy ( )
        {
            return true;
        }
    }

    public class Orange implements Fruit
    {
    }

    public class Banana implements Fruit
    {
        @Override
        public boolean isJuicy ( )
        {
            return false;
        }
    }
}

运行时。

new Orange().isJuicy(): true
new Banana().isJuicy(): false

更喜欢抽象类而不是默认方法

你问:

<块引用>

有没有更好的方法可以在没有默认方法和相应实现类中没有冗余代码的情况下实现这一点?

我建议您不要为此使用 default 接口方法。

向 Java 接口添加默认方法的想法和技术本身并不是一项功能,而是作为另一个问题的解决方案:在现有接口上改进功能以支持新的 lambda 功能,但不破坏数百万 Java 的现有代码程序员在向现有接口添加方法时会发生这种情况。通过在接口上发明 default 方法,Java 团队能够向现有接口添加更多方法,同时减轻所有现有实现对实现这些新方法的需求。新功能,不破坏代码,这是 Java 的标志。

State of the Lambda by Brian Goetz 2013-09中所述:

<块引用>

默认方法 (...) 的目的是使接口在最初发布后能够以兼容的方式进行演变。

我自己的观点是,程序员通常不会期望将行为内置到您的界面中。 Java 中接口的经典用法是根据 method signatures 定义契约,而不是定义行为(代码)。因此,仅作为最后的手段,才考虑添加添加行为(代码)作为默认方法。

相反,将您的接口定义为契约,没有默认方法。至少一开始没有默认方法;您稍后可能会像 Brian Goetz 和 Java 团队一样发现需要稍后添加默认方法。但从合同开始。

然后定义一个实现该接口的抽象类。要在各个子类之间共享的任何行为(代码)都可以移到这个抽象类中。

然后继续定义从抽象类继承的子类,具体类。

通过接口 + 抽象类 + 具体类的这种经典而通用的方法,您可以灵活地进行更改,并使测试更容易(使用存根而不是真正的类),同时从一个地方有效地共享代码,同时允许在何处覆盖需要。

答案 1 :(得分:1)

您没有做错任何事,尽管我会说抽象类更适合这种情况,当您在多个实现之间共享方法实现 (method1,method2) 时。

>

如果您仍然希望它是一个接口,请创建一个接口和一个扩展该接口的抽象类。