class DispatchingRateComputationFn implements RateComputationFn<RateComputation> {

  @Override
  public double explainRate(
      RateComputation computation,
      LocalDate startDate,
      LocalDate endDate,
      RatesProvider provider,
      ExplainMapBuilder builder) {

    // dispatch by runtime type
    if (computation instanceof FixedRateComputation) {
      // inline code (performance) avoiding need for FixedRateComputationFn implementation
      double rate = ((FixedRateComputation) computation).getRate();
      builder.put(ExplainKey.FIXED_RATE, rate);
      builder.put(ExplainKey.COMBINED_RATE, rate);
      return rate;
    } else if (computation instanceof FixedOvernightCompoundedAnnualRateComputation) {
      // inline code (performance) avoiding need for FixedRateComputationFn implementation
      double rate = ((FixedOvernightCompoundedAnnualRateComputation) computation).getRate();
      double simpleRate = ((FixedOvernightCompoundedAnnualRateComputation) computation).getSimpleRate();
      builder.put(ExplainKey.FIXED_RATE, rate);
      builder.put(ExplainKey.COMBINED_RATE, simpleRate);
      return rate;
    } else if (computation instanceof IborRateComputation) {
      return iborRateComputationFn.explainRate(
          (IborRateComputation) computation, startDate, endDate, provider, builder);
    } else if (computation instanceof IborInterpolatedRateComputation) {
      return iborInterpolatedRateComputationFn.explainRate(
          (IborInterpolatedRateComputation) computation, startDate, endDate, provider, builder);
    } else if (computation instanceof IborAveragedRateComputation) {
      return iborAveragedRateComputationFn.explainRate(
          (IborAveragedRateComputation) computation, startDate, endDate, provider, builder);
    } else if (computation instanceof OvernightAveragedRateComputation) {
      return overnightAveragedRateComputationFn.explainRate(
          (OvernightAveragedRateComputation) computation, startDate, endDate, provider, builder);
    } else if (computation instanceof OvernightCompoundedRateComputation) {
      return overnightCompoundedRateComputationFn.explainRate(
          (OvernightCompoundedRateComputation) computation, startDate, endDate, provider, builder);
    } else if (computation instanceof OvernightCompoundedAnnualRateComputation) {
      return overnightCompundedAnnualRateComputationFn.explainRate(
          (OvernightCompoundedAnnualRateComputation) computation, startDate, endDate, provider, builder);
    } else if (computation instanceof OvernightAveragedDailyRateComputation) {
      return overnightAveragedDailyRateComputationFn.explainRate(
          (OvernightAveragedDailyRateComputation) computation, startDate, endDate, provider, builder);
    } else if (computation instanceof InflationMonthlyRateComputation) {
      return inflationMonthlyRateComputationFn.explainRate(
          (InflationMonthlyRateComputation) computation, startDate, endDate, provider, builder);
    } else if (computation instanceof InflationInterpolatedRateComputation) {
      return inflationInterpolatedRateComputationFn.explainRate(
          (InflationInterpolatedRateComputation) computation, startDate, endDate, provider, builder);
    } else if (computation instanceof InflationEndMonthRateComputation) {
      return inflationEndMonthRateComputationFn.explainRate(
          (InflationEndMonthRateComputation) computation, startDate, endDate, provider, builder);
    } else if (computation instanceof InflationEndInterpolatedRateComputation) {
      return inflationEndInterpolatedRateComputationFn.explainRate(
          (InflationEndInterpolatedRateComputation) computation, startDate, endDate, provider, builder);
    } else {
      throw new IllegalArgumentException("Unknown Rate type: " + computation.getClass().getSimpleName());
    }
  }

  public  DispatchingRateComputationFn(
      RateComputationFn<IborRateComputation> iborRateComputationFn,
      RateComputationFn<IborInterpolatedRateComputation> iborInterpolatedRateComputationFn,
      RateComputationFn<IborAveragedRateComputation> iborAveragedRateComputationFn,
      RateComputationFn<OvernightCompoundedRateComputation> overnightCompoundedRateComputationFn,
      RateComputationFn<OvernightCompoundedAnnualRateComputation> overnightCompundedAnnualRateComputationFn,
      RateComputationFn<OvernightAveragedRateComputation> overnightAveragedRateComputationFn,
      RateComputationFn<OvernightAveragedDailyRateComputation> overnightAveragedDailyRateComputationFn,
      RateComputationFn<InflationMonthlyRateComputation> inflationMonthlyRateComputationFn,
      RateComputationFn<InflationInterpolatedRateComputation> inflationInterpolatedRateComputationFn,
      RateComputationFn<InflationEndMonthRateComputation> inflationEndMonthRateComputationFn,
      RateComputationFn<InflationEndInterpolatedRateComputation> inflationEndInterpolatedRateComputationFn);

}