You should create a Factory class to help you with this.
interface IFactoryProduct{ AbstractProduct getProduct(AbstractCondition condition) throws Exception; }
This will be your interface, you just need to implement it like this.
class FactoryProduct implements IFactoryProduct{ public AbstractProduct getProduct(AbstractCondition condition) throws Exception{ return (AbstractProduct)getClass().getMethod("getProduct", condition.getClass()).invoke(this, condition); } public ProductA getProduct(ConditionA condition){ return new ProductA(); } public ProductB getProduct(ConditionB condition){ return new ProductB(); }
}
Using reflection to redirect with the correct method will do the trick. it's possible for a subclass if you want.
EDIT:
Example:
List<AbstractCondition> list = new ArrayList<AbstractCondition>(); list.add(new ConditionA()); list.add(new ConditionB()); for(AbstractCondition c : list){ try { System.out.println(f.getProduct(c)); } catch (Exception ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); } }
labo.ProductA@c17164
labo.ProductB@1fb8ee3
A more complex version of reflection, allowing you to get a subclass:
public AbstractProduct getProduct(AbstractCondition condition) throws Exception{ Method m = getMethodFor(condition.getClass()); if(m == null ) throw new Exception("No method for this condition " + condition.getClass().getSimpleName()); else return (AbstractProduct) m.invoke(this, condition); } private Method getMethodFor(Class<? extends AbstractCondition> clazz ) throws Exception{ try { return getClass().getMethod("getProduct", clazz); } catch (NoSuchMethodException ex) { if(clazz.getSuperclass() != AbstractCondition.class){ return getMethodFor((Class<? extends AbstractCondition>)clazz.getSuperclass()); } return null; } }
This allows me to send a ConditionC extending ConditionB to build the same product that ConditionB has. Interesting for a complex heritage.
Axelh source share