静态方法中的重复代码

Duplicate code in static methods

我在 JAVA 中实现了两个阅读器。见下文:

public final class ReaderA {
  public ReaderA() {}

  public static int read(final File file) {
    final byte[] data = Files.readAllbytes(file.toPath());
    return read(data);
  }

  public static int read(final byte[] data) {
    // do somethingA
  }

  ...// and some other methods
}


public final class ReaderB {
  public ReaderB() {}

  // this method is exactly the same as in ReaderA
  public static int read(final File file) {
    final byte[] data = Files.readAllbytes(file.toPath());
    return read(data);
  }

  // this is implemented different from the one in ReaderA
  public static int read(final byte[] data) {
    // do somethingB
  }

  ...// and the same other methods as in ReaderA
}

问题。避免重复代码的最佳方法是什么?

我试图在新的摘要 class Reader 中提取重复代码,并尝试制作 read(final byte[] data) 摘要并在 subclasses ReaderAReaderB。它不会工作,因为这些方法是静态的。

我认为您首先需要问自己几个问题:

  1. 我真的需要两个静态方法吗?
  2. 'methods' 或 class 的通用代码是什么?
  3. 是否可以制作一个抽象class来编写这样的实现并让 ReaderA 和 ReaderB 扩展它,减少重复代码?
  4. 你是否应该有一个父 class 然后创建 class 从上面继承的元素?

我认为您应该阅读 SOLID 原则,特别是 Open/Closed 原则和依赖倒置

如果您使用的是 Java SE 8,您可以将静态方法放在接口中。 Java 接口静态方法类似于默认方法,只是我们不能在实现中覆盖它们类。如果实施不当,此功能可帮助我们避免出现不良结果 类.

有几种可能性:

  1. 从其中一个 class 中删除该方法并使用继承(您不能为静态方法调用 super.myMethod(),但除非您覆盖它,否则它会起作用)

我不建议这样做:您可能会在子 class 中获得其他可用的方法,而您可能不想这样做。

  1. 将它提取到一个通用的超级class,用于classes

  2. 从一个 class 调用另一个方法。如果它们都保持相同的功能,这将起作用

我不确定用静态方法保留此实现是否是您能做的最好的,但如果是这样,您可以添加一个 Function 参数。

public class Reader {

    public static int read(final File file, Function<byte[], Integer> reader) {
        final byte[] data = Files.readAllbytes(file.toPath());
        return reader.apply(data);
    }

}

然后像这样使用它:

public final class ReaderA {
    public static int read(final File file) {
        return Reader.read(file, ReaderA::read);
    }
    public static int read(final byte[] data) {
        // do somethingA
    }
}

自从Java8中引入functional interfaces and method references以来,几乎没有无法避免的重复代码部分。

除非您从 read(byte[]) 中删除 static 修饰符并创建实例,否则您将无法使用继承来帮助您。

static 方法的行为不像实例方法,不能被覆盖。相反,super class 和 sub class 都有单独的方法,需要使用 class 名称进行限定。上拉read(File)表示总是调用超class的read(byte[])。您仍然必须将 read(File) 复制到每个子 class 以使其使用 class 自己的 read(byte[]) 中的代码也显示了这一点。

作为参考,请阅读这个问题及其答案:Are static methods inherited in Java?

为了说明:您拥有的两个 read(File) 方法是 而不是 "exactly the same",正如您在代码片段中所说的那样。他们不会同时调用 this.read(data),而是分别调用 ReaderA.read(data)ReaderB.read(data)。查看 read(byte[]) 调用如何调用两个完全不同的、不可覆盖的方法。


如果您有能力,我建议您以一种不太静态的方式重写读者:

interface Reader
{
    default int read(File file)
    {
        final byte[] data = Files.readAllbytes(file.toPath());
        return read(data);
    }

    int read(byte[] data);
}

class ReaderA
    implements Reader
{
    int read(byte[] data)
    {
        // do somethingA
    }
}

class ReaderB
    implements Reader
{
    int read(byte[] data)
    {
        // do somethingB
    }
}

请注意 read(File) 现在对于所有实施的 class 都是一样的。当然,您必须将调用方法的方式从 ReaderX.read() 更改为 new ReaderX().read().