println(String)的接口

时间:2019-07-02 15:20:14

标签: java println duck-typing method-signature

我想编写将打印一些行的Java代码(例如,一种方法)。

打印对象应由调用者提供。我希望我的代码关心那个对象到底是什么,并简单地调用该对象的println()println(String)方法。无论该对象是java.io.PrintStream(例如System.out)还是java.io.PrintWriter(例如,调用者使用new PrintWriter(System.out)new PrintWriter(new ByteArrayOutputStream())构造),都应该起作用。

如果“可打印lineable”对象的潜在类将共享一些强制使用println()println(String)方法的接口,这将很容易。但是他们没有。

那么我要怎么写才能接收这样的对象而又不写DRY principle,而是写两次本质上相同的实现,只是换出类型(就像我在简单地重载函数时那样) )?

public void sayHello( ??? outThingy) {
    outThingy.println("Hello World");
    outThingy.println();
    // This just a minimal example.
    // The real implementation might be more involved
    // and non-trivial, so that avoiding duplication
    // becomes a real concern.
};


// sayHello should be usable like this:

sayHello(System.out);


// but also like this:

baos = new ByteArrayOutputStream();
pw = new PrintWriter(baos)

sayHello(pw);

pw.flush();
System.out.println(baos.toString());

或者PrintStreamPrintWriter不共享这样一个接口的事实是否应被视为表明它们在提供打印行方式方面不可互换? (而不是指定这些类别时的某种历史监督。)

3 个答案:

答案 0 :(得分:2)

最简单的方法就是使用接受PrintWriter的版本和接受PrintStream的版本重载该方法:

public void sayHello(PrintStream outThingy) {
    outThingy.println("Hello World");
    outThingy.println();
};
public void sayHello(PrintWriter outThingy) {
    outThingy.println("Hello World");
    outThingy.println();
};

答案 1 :(得分:2)

这是一种您可以做到的方法,至少可以使outThingy的客户保持干燥。但是,您将不得不权衡有效地参加几个WET课程。尽管如此,代码量却很少。

// Printer allows for a common interface
interface Printer {
  void println(String line);
  void println();
}

// Used with PrintStream
class StreamPrinter implements Printer {
  private PrintStream ps;

  public StreamPrinter(PrintStream ps) {
    this.ps = ps;
  }

  @Override
  public void println(String line) {
    ps.println(line);
  }

  @Override
  public void println() {
    ps.println();
  }
}

// Used with PrintWriter
class TypeWriter implements Printer {
  private PrintWriter pw;

  public TypeWriter(PrintWriter pw) {
    this.pw = pw;
  }

  @Override
  public void println(String line) {
    pw.println(line);
  }

  @Override
  public void println() {
    pw.println();
  }
}

class Talker {
  // This class doesn't care!
  void sayHello(Printer printer) {
    printer.println("Hello world");
    printer.println();
  }
}

答案 2 :(得分:1)

您可能对另一种更实用的方法感兴趣。不必担心每种类型提供的功能以及如何在它们之间找到共同的interface,您可以通过使用ConsumerRunnable来表示,从而用更少的代码实现相同的目的。 println种方法。

// This is the common class
class FuncPrinter {
  private Consumer<String> consumer;
  private Runnable runnable;

  public FuncPrinter(PrintWriter writer) {
    consumer = writer::println;
    runnable = writer::println;
  }

  public FuncPrinter(PrintStream stream) {
    consumer = stream::println;
    runnable = stream::println;
  }

  public void println(String line) {
    consumer.accept(line);
  }

  public void println() {
    runnable.run();
  }
}

class Talker {    
  void sayHello(FuncPrinter fp) {
    fp.println("Hello World");
    fp.println();
  }
}

您可以像这样使用它:

Talker t = new Talker();

FuncPrinter fp = new FuncPrinter(System.out);
t.sayHello(fp);

ByteArrayOutputStream ostream = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(ostream);
fp = new FuncPrinter(pw);
t.sayHello(fp);

fp = new FuncPrinter(
  line -> System.out.println(line),
  () -> System.out.println(42));
t.sayHello(fp);