使用 Generics 的接口
假设你要定义一个允许从不同类型的通道(例如 AMQP,JMS 等)发布/使用数据的接口,但你希望能够切换实现细节……
让我们定义一个可以在多个实现中重用的基本 IO 接口:
public interface IO<IncomingType, OutgoingType> {
void publish(OutgoingType data);
IncomingType consume();
IncomingType RPCSubmit(OutgoingType data);
}
现在我可以实例化该接口,但由于我们没有这些方法的默认实现,因此在实例化它时需要实现:
IO<String, String> mockIO = new IO<String, String>() {
private String channel = "somechannel";
@Override
public void publish(String data) {
System.out.println("Publishing " + data + " to " + channel);
}
@Override
public String consume() {
System.out.println("Consuming from " + channel);
return "some useful data";
}
@Override
public String RPCSubmit(String data) {
return "received " + data + " just now ";
}
};
mockIO.consume(); // prints: Consuming from somechannel
mockIO.publish("TestData"); // Publishing TestData to somechannel
System.out.println(mockIO.RPCSubmit("TestData")); // received TestData just now
我们也可以使用该接口做一些更有用的事情,假设我们想用它来包装一些基本的 RabbitMQ 函数:
public class RabbitMQ implements IO<String, String> {
private String exchange;
private String queue;
public RabbitMQ(String exchange, String queue){
this.exchange = exchange;
this.queue = queue;
}
@Override
public void publish(String data) {
rabbit.basicPublish(exchange, queue, data.getBytes());
}
@Override
public String consume() {
return rabbit.basicConsume(exchange, queue);
}
@Override
public String RPCSubmit(String data) {
return rabbit.rpcPublish(exchange, queue, data);
}
}
假设我现在想要使用这个 IO 界面来计算自上次系统重启以来访问我网站的次数,然后能够显示总访问次数 - 你可以这样做:
import java.util.concurrent.atomic.AtomicLong;
public class VisitCounter implements IO<Long, Integer> {
private static AtomicLong websiteCounter = new AtomicLong(0);
@Override
public void publish(Integer count) {
websiteCounter.addAndGet(count);
}
@Override
public Long consume() {
return websiteCounter.get();
}
@Override
public Long RPCSubmit(Integer count) {
return websiteCounter.addAndGet(count);
}
}
现在让我们使用 VisitCounter:
VisitCounter counter = new VisitCounter();
// just had 4 visits, yay
counter.publish(4);
// just had another visit, yay
counter.publish(1);
// get data for stats counter
System.out.println(counter.consume()); // prints 5
// show data for stats counter page, but include that as a page view
System.out.println(counter.RPCSubmit(1)); // prints 6
实现多个接口时,不能两次实现相同的接口。这也适用于通用接口。因此,以下代码无效,并将导致编译错误:
interface Printer<T> {
void print(T value);
}
// Invalid!
class SystemPrinter implements Printer<Double>, Printer<Integer> {
@Override public void print(Double d){ System.out.println("Decimal: " + d); }
@Override public void print(Integer i){ System.out.println("Discrete: " + i); }
}