Method Reference

我有個透過JNA去存取硬體資料的程式:

public interface Bus extends Library {
	Bus INSTANCE = (Bus) Native.loadLibrary( "buslib", Bus.class);
 
	boolean sendData(byte bus, byte data[]);
	boolean getData(byte bus, byte data[]);
}
 
public boolean sendData(byte bus, byte data[]){
	synchronized (Bus.class) {
		return Bus.INSTANCE.sendData(bus, data);
	}
}
 
public boolean getData(byte bus, byte data[]){
	synchronized (Bus.class) {
		return Bus.INSTANCE.getData(bus, data);
	}
}
某天有了需要做存取控管需求,因此我在Bus Library介面上增加了兩個methods:
boolean lockBus(byte bus);
boolean releaseBus(byte bus);
而sendData中,在實際請求前會先lockBus,使用後再releaseBus:
public boolean sendData(byte bus, byte data[]){
	synchronized (Bus.class) {
		try {
			boolean ret = false;
			if (!(ret = Bus.INSTANCE.lockBus(bus))) {
				return ret;
			}
			return Bus.INSTANCE.sendData(bus, data);
		} finally {
			Bus.INSTANCE.releaseBus(bus);
		}
	}
}
問題是: 如果我有10個bus相關操作,不就要寫很多一樣的code嗎?

一開始我就想,除了aop、intercepter等方式外,function pointer應該就能解決我的問題: 只要有一個method會在critical action前後做lock與release就可以了。類似以下:

void busAction(Function* criticalAction){
	lockAndWait();
 
	criticalAction->invoke();
 
	release();
}
最後宣告一個名為BusAction的FunctionalInterface:
@FunctionalInterface
public interface BusAction {
	boolean invoke();
}
而我處理lock與release的method如下:
private boolean invokeBusAction(byte bus, BusAction action){
	synchronized (Bus.class) {
		try {
			boolean ret = false;
			if (!(ret = Bus.INSTANCE.lockBus(bus))) {
				return ret;
			}		
		return action.invoke();
		} finally {
			Bus.INSTANCE.releaseBus(bus);
		}
	}
}
最後就是sendData與getData:
public boolean sendData(byte bus, byte data[]){
	return invokeBusAction(bus, ()->{
		return Bus.INSTANCE.sendData(bus, data);
	});
}
 
public boolean getData(byte bus, byte data[]){
	return invokeBusAction(bus, ()->{
		return Bus.INSTANCE.getData(bus, data);
	});
}
透過以上方法,可以讓我大幅減少duplicated code。

如果不想額外增加Interface,也可以直接使用Runable或Callable,取決於你是否要讓語義更清楚而已。