使用 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); }
}