Java 我应该如何重构此方法以遵守Bob叔叔规则,即参数不超过2或3个?
我有一个很重的方法,可以根据多个参数计算合同的利息。我确实需要这些参数中的每一个,但这违反了Bob叔叔的规则,即参数不超过2或3个Java 我应该如何重构此方法以遵守Bob叔叔规则,即参数不超过2或3个?,java,refactoring,Java,Refactoring,我有一个很重的方法,可以根据多个参数计算合同的利息。我确实需要这些参数中的每一个,但这违反了Bob叔叔的规则,即参数不超过2或3个 public double calculInteretsParPeriode(double encours, double tauxWithMarge, Date dtEch, Date dtEchPrec, boolean isFirstEcheanceInterets, Periode periodiciteK,
public double calculInteretsParPeriode(double encours, double tauxWithMarge, Date dtEch, Date dtEchPrec, boolean isFirstEcheanceInterets, Periode periodiciteK,
BaseCalcul baseCalcul, TauxProportionnelOuEquivalent tauxProportionnelOuEquivalent, int tauxNDecimal,
Periode periodiciteI, PeriodeCalculInterets periodeCalculInterets) {
...
int nMensualiteAnPlusGrand = CalculMensualite.calculNMensualiteParAnsMax(periodiciteK, periodiciteI);
double coeffI = CalcEmprunt2014.calcCoeffInterets(
baseCalcul.getNumerateur(),
baseCalcul.getDenominateur(),
dtEch,
dtEchPrec,
nMensualiteAnPlusGrand,
baseCalcul.getProrata(),
isFirstEcheanceInterets
);
//les intérêts sont calculés avec le taux + la marge du contrat
switch (tauxProportionnelOuEquivalent) {
case PROPORTIONNEL:
return MathUtils.round2D(encours * MathUtils.arrondi(tauxWithMarge, tauxNDecimal) / 100.0 * coeffI);
case EQUIVALENT:
return MathUtils.round2D(encours * (Math.pow((1 + MathUtils.arrondi(tauxWithMarge, tauxNDecimal) / 100), coeffI) - 1));
case PROPORTIONNEL_EQUIVALENT:
return MathUtils.round2D(encours * (MathUtils.arrondi((Math.pow((1 + MathUtils.arrondi(tauxWithMarge, tauxNDecimal) / 100), coeffI) - 1) * nMensualiteAnPlusGrand, tauxNDecimal + 2) * coeffI));
default:
throw new GenericRuntimeException("Méthode de calcul des intérêts non pris en charge: " + tauxProportionnelOuEquivalent);
}
}
我尝试过使用构建器模式,但这看起来像是作弊,因为我只是将所需的变量移动到类字段中,仍然需要将它们传递给构建器,这感觉很混乱:
ew CalculInteretsParPeriodeBuilder()
.withEncours(10000)
.withTauxWithMarge(1.0)
.withDtEch(DateCalculs.getDate(2019, Month.FEBRUARY, 1))
.withDtEchPrec(DateCalculs.getDate(2018, Month.FEBRUARY, 1))
.withIsFirstEcheanceInterets(false)
.withPeriodiciteI(Periode.ANNUELLE)
.withPeriodiciteK(Periode.ANNUELLE)
.withTauxNDecimal(2)
.withPeriodeCalculInterets(PeriodeCalculInterets.PAR_PERIODE)
.withBaseCalcul(BaseCalcul.BC_360360)
.withTauxProportionnelOuEquivalent(TauxProportionnelOuEquivalent.EQUIVALENT)
.build()
.calculInteretsParPeriode()
当您有多个可交换(可选)的参数时,生成器模式非常有用。然后您可以将它们链接在一起并配置您的对象。但最终他们只初始化了一个对象。因此,如果您有20个参数,并且您的对象总是需要同样的10个参数才能正常工作,那么将其放入构建器模式是不值得的 让我们假设这是最简单的:
new CalculInteretsParPeriodeBuilder()
.withEncours(10000)
.withTauxWithMarge(1.0)
.withDtEch(DateCalculs.getDate(2019, Month.FEBRUARY, 1))
.withDtEchPrec(DateCalculs.getDate(2018, Month.FEBRUARY, 1))
.withIsFirstEcheanceInterets(false);
那么只调用构造函数就更短了:
CalculInteretsParameters params = new CalculInteretsParameters(
10000,
1.0,
DateCalculs.getDate(2019, Month.FEBRUARY, 1),
DateCalculs.getDate(2018, Month.FEBRUARY, 1),
false
);
在我看来,一些简单的setter
调用所有可选参数没有什么错:
params.setPeriodiciteI(Periode.ANNUELLE);
params.setPeriodiciteK(Periode.ANNUELLE);
if(reallyNecessary){ // see? way more dynamic :)
params.setTauxNDecimal(2);
params.setPeriodeCalculInterets(PeriodeCalculInterets.PAR_PERIODE);
}else{
params.setBaseCalcul(BaseCalcul.BC_360360);
}
对你来说,我不会用它。只需初始化一个参数对象(根据需要动态地)并将其传递给计算方法
编辑
抱歉,要回答您的问题,我将使用参数类:
CalculInteretsParameters params = new CalculInteretsParameters();
params.setTauxWithMarge(1.0); // set all your dates, numbers and parameters
params.setPeriodicite(2);
...
// then call your method (maybe even with some dynamic values)
calculInteretsParPeriode(params, someDynamicValue);
为了展示一些代码,我使用了一个生成器作为“常规”参数,并在calcul()方法的签名中使用了更多的“特定”参数,从而完成了@Gamedroid建议的工作 及
所以非常感谢您可以创建一个单独的类来存储值,比如说,
MyCalculationParameters
class。然后将这一个对象传递到方法中。他们已经是一个“巨大”的对象,包含了计算所需的所有参数,但这是我的整个“合同”,它有150多个字段。我们过去只是将契约传递给所有方法,但对于像这样的一些用例来说并不方便,在这些用例中,这个方法需要从不同的上下文中调用,而我们没有契约对象。是的,150个字段相当多。你不能把它们组合在一起,创建“子对象”,然后你可以用它来调用不同的方法吗?因此,保留“Contract”类,而不是DtEch
,DtEchPrec
,DtEchProch
,DtEchFin
。。。。您创建了一个类Echeances
,在其中放置所有这些日期、一些其他相关值,并将该对象传递给您的合同。与Taux
等相关的所有参数都是一样的。是的,实际上在所有这些参数中,它们都是合同本身的一部分:-PeriodiciteI-PeriodiciteK-TauxNDecimal-periodicalculinterets-BaseCalcul-tauxproportionelouequivalent,可以重新组合,其他参数是动态字段,具体取决于我的技术计算interets。这肯定是我应该在方法中将“一般契约”参数与动态参数分开的东西,因此我应该将所有这些参数从我的实际方法calculInteretsParPeriode
传递到容器对象CalculInteretsParameters
?要使用所有参数构建此容器,请使用Factory或Builder模式?我只是觉得我是在回避问题,而不是面对它。不过,我看不出有其他/更好的方法来做这件事。。如何更好地使用参数类而不是将所有参数直接传递给方法?可以重用参数类。或者最好是参数对象。重新计算并更新其值,然后继续。无需从计算方法返回它,也无需将所有参数再次传递给其他方法。但我不认为有一个通用规则可以应用于“清理”方法调用。如果有一个特定的方法真的需要50个参数才能工作,那么这并不是一切的结束。只要不是所有方法都有这么多参数,只要不传递不需要的值,我就应该尝试实现将常规参数与动态参数分离的好主意。可能使用包含所有常规参数的构造函数的BuilderPattern,并使用setter添加动态参数。
public class CalculInteretsParPeriodeBuilder {
private ContratBasic contratBasic;
private DefinitionTaux contratTaux;
private Periode periodiciteK;
private Periode periodiciteI;
private BaseCalcul baseCalcul;
private TauxProportionnelOuEquivalent tauxProportionnelOuEquivalent;
private Integer tauxNDecimal;
private PeriodeCalculInterets periodeCalculInterets = PeriodeCalculInterets.PAR_PERIODE;
public CalculInteretsParPeriodeBuilder withContratBasic(ContratBasic contratBasic) {
this.contratBasic = contratBasic;
return this;
}
public CalculInteretsParPeriodeBuilder withContratTaux(DefinitionTaux contratTaux) {
this.contratTaux = contratTaux;
return this;
}
public CalculInteretsParPeriodeBuilder withPeriodiciteK(Periode periodiciteK) {
this.periodiciteK = periodiciteK;
return this;
}
public CalculInteretsParPeriodeBuilder withBaseCalcul(BaseCalcul baseCalcul) {
this.baseCalcul = baseCalcul;
return this;
}
public CalculInteretsParPeriodeBuilder withBaseCalcul(com.dev1.seldon.infodette.beans.contrat2014.commons.enums.BaseCalcul baseCalcul) {
this.baseCalcul = new BaseCalcul(baseCalcul);
return this;
}
public CalculInteretsParPeriodeBuilder withTauxProportionnelOuEquivalent(TauxProportionnelOuEquivalent tauxProportionnelOuEquivalent) {
this.tauxProportionnelOuEquivalent = tauxProportionnelOuEquivalent;
return this;
}
public CalculInteretsParPeriodeBuilder withTauxNDecimal(int tauxNDecimal) {
this.tauxNDecimal = tauxNDecimal;
return this;
}
public CalculInteretsParPeriodeBuilder withPeriodiciteI(Periode periodiciteI) {
this.periodiciteI = periodiciteI;
return this;
}
public CalculInteretsParPeriodeBuilder withPeriodeCalculInterets(PeriodeCalculInterets periodeCalculInterets) {
this.periodeCalculInterets = periodeCalculInterets;
return this;
}
public CalculInteretsParPeriode build() {
if (contratBasic != null && contratTaux != null) {
this.periodiciteK = contratBasic.getPeriodiciteK();
this.periodiciteI = contratTaux.getPeriodiciteI();
this.baseCalcul = contratTaux.getBaseCalculI();
this.tauxProportionnelOuEquivalent = contratTaux.getTauxProportionnelOuEquivalent();
this.tauxNDecimal = contratTaux.getTauxNDecimal();
this.periodeCalculInterets = contratTaux.getPeriodeCalculInteret();
}
if (periodiciteK == null) throw new MandatoryMethodParameterException("periodiciteK");
if (baseCalcul == null) throw new MandatoryMethodParameterException("baseCalcul");
if (tauxProportionnelOuEquivalent == null) throw new MandatoryMethodParameterException("tauxProportionnelOuEquivalent");
if (tauxNDecimal == null) throw new MandatoryMethodParameterException("tauxNDecimal");
if (periodiciteI == null) throw new MandatoryMethodParameterException("periodiciteI");
return new CalculInteretsParPeriode(periodiciteK, baseCalcul, tauxProportionnelOuEquivalent, tauxNDecimal, periodiciteI, periodeCalculInterets);
}
}
public class CalculInteretsParPeriode {
private PeriodeCalculInterets periodeCalculInterets;
private Periode periodiciteI;
private Periode periodiciteK;
private TauxProportionnelOuEquivalent tauxProportionnelOuEquivalent;
private int tauxNDecimal;
private BaseCalcul baseCalcul;
public CalculInteretsParPeriode(Periode periodiciteK, BaseCalcul baseCalcul, TauxProportionnelOuEquivalent tauxProportionnelOuEquivalent, int tauxNDecimal,
Periode periodiciteI, PeriodeCalculInterets periodeCalculInterets) {
this.periodiciteK = periodiciteK;
this.periodiciteI = periodiciteI;
this.baseCalcul = baseCalcul;
this.tauxProportionnelOuEquivalent = tauxProportionnelOuEquivalent;
this.tauxNDecimal = tauxNDecimal;
this.periodeCalculInterets = periodeCalculInterets;
}
public double calculInteretsParPeriode(double encours, double tauxWithMarge, Date dtEch, Date dtEchPrec, boolean isFirstEcheanceInterets) {
if (dtEch == null) throw new MandatoryMethodParameterException("dtEch");
if (dtEchPrec == null) throw new MandatoryMethodParameterException("dtEchPrec");
int nMensualiteAnPlusGrand = CalculMensualite.calculNMensualiteParAnsMax(periodiciteK, periodiciteI);
double coeffI = CalcEmprunt2014.calcCoeffInterets(
baseCalcul.getNumerateur(),
baseCalcul.getDenominateur(),
dtEch,
dtEchPrec,
nMensualiteAnPlusGrand,
baseCalcul.getProrata(),
isFirstEcheanceInterets
);
return MathUtils.round2D(encours * MathUtils.arrondi(tauxWithMarge, tauxNDecimal) / 100.0 * coeffI);
}
}