我想为下面的ADT得到一些批评。这只是一个基本的ADT,将被输入到一个TVM计算器。主要目的是对输入错误进行初始化和纠正。
完全披露:我是建模后,代码完成2准则。您应该注意到,if语句首先声明名义情况,然后在else语句中进行错误检查。我正试图尽可能接近这本书中的指导方针。然而,很难掌握900+页面的资料。除了类的不完整之外,我遗漏了什么,或者代码完成了什么?
public class TVMData
{
public decimal DiscountRate;
public decimal PeriodLength;
public decimal CashFlowFromAsset;
public decimal CashOutFlow;
public decimal PaymentFrequency;
decimal DiscountedCashFlow;
public TVMData(){}
public TVMData(double discountRate, double periodLength, double cashFlowFromAsset, double cashOutFlow, PaymentPerPeriod paymentFrequency= PaymentPerPeriod.Annual)
: this(Convert.ToDecimal(discountRate), Convert.ToDecimal(periodLength), Convert.ToDecimal(cashFlowFromAsset), Convert.ToDecimal(cashOutFlow), paymentFrequency){}
public TVMData (decimal discountRate, decimal periodLength, decimal cashFlowFromAsset, decimal cashOutFlow, PaymentPerPeriod paymentFrequency= PaymentPerPeriod.Annual)
{
this.PaymentFrequency = Convert.ToDecimal(paymentFrequency);
if (discountRate>=0m)
{
this.DiscountRate= discountRate;
if (periodLength >= 1m)
{
this.PeriodLength = periodLength;
if(cashFlowFromAsset >= 0m)
{
this.CashFlowFromAsset=cashFlowFromAsset;
if(cashOutFlow <= 0m)
{
this.CashOutFlow = cashOutFlow;
}
else
{
throw new ArgumentOutOfRangeException("Cash Out Flow must be less than or equal to Zero", "cashOutFlow");
}
}
else
{
throw new ArgumentOutOfRangeException("Cash Flow From Asset must be greater than Zero","cashFlowFromAsset");
}
}
else
{
throw new ArgumentOutOfRangeException("Period Length must be equal or greater than One", "periodLength");
}
}
else
{
throw new ArgumentOutOfRangeException("Discount Rate must be greater than Zero", "discountRate");
}
}
}发布于 2015-02-25 07:01:50
在第15章中,您似乎是在引用以下建议:
简单的if -然后语句在编写if语句时遵循以下准则:首先通过代码编写标称路径;然后编写不寻常的情况,编写代码,以便代码中的正常路径是清晰的。确保罕见的情况不会掩盖正常的执行过程。这对于可读性和性能都很重要。…将正常情况放在if之后,而不是在其他情况之后,您通常希望先处理这个情况。这符合将决策所产生的代码尽可能地隐藏在决策中的一般原则。
我认为忽略这些建议是很安全的。一个主要考虑因素是,这些例子不涉及例外情况。在没有异常的情况下编写代码时,不断深化的嵌套所形成的代码箭头具有很好的意义。特别是在C语言中,用这个成语编写代码是很常见的:
Resource *ptr1 = malloc(…);
if (SUCCESS == iffy_operation1_involving(ptr1)) {
Resource *ptr2 = malloc(…);
if (SUCCESS == iffy_operation2_involving(ptr2)) {
…
}
free(ptr2);
}
free(ptr1);但是C#有异常和自动内存管理。用这种方式编写代码没有意义了。相反,一个更重要的观察是,成功只有一种方式,但在这一过程中却有许多失败的机会。因此,最好是线性地编写代码,而不嵌套:
public TVMData(decimal discountRate, decimal periodLength, decimal cashFlowFromAsset, decimal cashOutFlow, PaymentPerPeriod paymentFrequency= PaymentPerPeriod.Annual)
{
this.PaymentFrequency = Convert.ToDecimal(paymentFrequency);
if (discountRate < 0m) throw new ArgumentOutOfRangeException("Discount Rate must be greater than Zero", "discountRate");
this.DiscountRate = discountRate;
if (periodLength < 1m) throw new ArgumentOutOfRangeException("Period Length must be equal or greater than One", "periodLength");
this.PeriodLength = periodLength;
if (cashFlowFromAsset < 0m) throw new ArgumentOutOfRangeException("Cash Flow From Asset must be greater than Zero","cashFlowFromAsset");
this.CashFlowFromAsset = cashFlowFromAsset;
if (cashOutFlow > 0m) throw new ArgumentOutOfRangeException("Cash Out Flow must be less than or equal to Zero", "cashOutFlow");
this.CashOutFlow = cashOutFlow;
}请注意,“抽象数据类型”是一个非常漏洞百出的抽象。由于一切都是公开的,因此可以通过这样做来绕过所有验证:
TVMData tvm = new TVMData();
tvm.DiscountRate = -1m;
tvm.CashFlowFromAsset = -1000000m;如果希望以该样式填充数据,则应该使用属性而不是公开公共成员。
发布于 2015-02-25 12:04:11
除了两个我都同意的现有评论之外,我还怀疑为您的方法设置五个参数是否明智,特别是考虑到前四个参数是相同的类型(十进制)。我更喜欢构造一个“参数类”。
public class DataParameters
{
public decimal DiscountRate { get; set; }
public decimal PeriodLength { get; set; }
// etc.
}(请注意,DataParameters是一个坏名字,它应该是一个更有意义的名称。)
然后像这样填充该类:
var dataParameters = new DataParameters
{
DiscountRate = discountRate;
PeriodLength = periodLength;
/// etc.
}这种方式不太容易出错:如果在调用该方法时意外切换了discountRate和periodLength,该怎么办?(当然,使用命名参数可以防止这种情况发生。)
您的构造函数将变成:
public TVMData (DataParameters dataParameters)
{
if (dataParameters.DiscountRate < 0m)
throw new ArgumentOutOfRangeException("Discount Rate must be greater than Zero", "discountRate");
this.DiscountRate = dataParameters.DiscountRate;
}这样就很容易添加额外的参数。
或者,在所有验证完成后,您可以简单地存储DataParameters而不是DiscountRate等等,以遵守干的。
注意,类名TVMData违反了微软的大写规则:“只将首字母首字母大写为三个或三个以上字符”“只将首字母首字母大写为三个或三个以上字符”。
https://codereview.stackexchange.com/questions/82546
复制相似问题