To begin with, there is two cases which can be coalesced into one: When the orders are different:
if(buyOrder instanceof MarketOrder && sellOrder instanceof LimitOrder){
return ((LimitOrder)sellOrder).getUnitPrice();
}
if(buyOrder instanceof LimitOrder && sellOrder instanceof MarketOrder){
return ((LimitOrder)buyOrder).getUnitPrice();
}
To:
if(!buyOrder.getClass().equals(LimitOrder.getClass())){
return ((LimitOrder)sellOrder).getUnitPrice();
}
On the other hand, you can use orders classes as indexes of a map containing function objects. That way you can expand your funcionality by just adding elements to this map.
You can encapsulate calculation algorithms using anonymous inner classes implementing an interface like:
public interface IFunction {
public Long execute(Order oA, Order oB);
}
And decide which behaviour executed accessing this map using order classes:
Map<Class, Map<Class, IFunction>> opClass2calcAlgorithm = new HashMap();
IFunction market_market = new IFunction() {
@Override
public Long execute(Order a, Order b) {
return tradeRepository.getLastPrice();
}
};
IFunction market_limit = new IFunction() {
@Override
public Long execute(Order a, Order b) {
return ((LimitOrder)a).getUnitPrice();
}
};
Map<Class, IFunction> marketMap = new HashMap();
marketMap.put(MarketOrder.class, market_market);
marketMap.put(LimitOrder.class, market_limit);
opClass2calcAlgorithm.put(marketMap);
Finally, your getUnitPrice
method can be implemented like this:
public Long getUnitPrice(Order buyOrder, Order sellOrder){
long ret = 0L;
Map<Class, IFunction> firstLevel = opClass2calcAlgorithm.get(buyOrder.getClass());
if(firstLevel == null) return ret;
IFunction calcAlg = firstLevel.get(sellOrder.getClass());
if(calcAlg == null) return ret;
ret = calcAlg.execute(buyOrder, sellOrder);
return ret;
}