首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TVM计算器的ADT

TVM计算器的ADT
EN

Code Review用户
提问于 2015-02-25 06:10:10
回答 2查看 224关注 0票数 2

我想为下面的ADT得到一些批评。这只是一个基本的ADT,将被输入到一个TVM计算器。主要目的是对输入错误进行初始化和纠正。

完全披露:我是建模后,代码完成2准则。您应该注意到,if语句首先声明名义情况,然后在else语句中进行错误检查。我正试图尽可能接近这本书中的指导方针。然而,很难掌握900+页面的资料。除了类的不完整之外,我遗漏了什么,或者代码完成了什么?

代码语言:javascript
复制
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");
        }


     }

}
EN

回答 2

Code Review用户

发布于 2015-02-25 07:01:50

第15章中,您似乎是在引用以下建议:

简单的if -然后语句在编写if语句时遵循以下准则:首先通过代码编写标称路径;然后编写不寻常的情况,编写代码,以便代码中的正常路径是清晰的。确保罕见的情况不会掩盖正常的执行过程。这对于可读性和性能都很重要。…将正常情况放在if之后,而不是在其他情况之后,您通常希望先处理这个情况。这符合将决策所产生的代码尽可能地隐藏在决策中的一般原则。

我认为忽略这些建议是很安全的。一个主要考虑因素是,这些例子不涉及例外情况。在没有异常的情况下编写代码时,不断深化的嵌套所形成的代码箭头具有很好的意义。特别是在C语言中,用这个成语编写代码是很常见的:

代码语言:javascript
复制
Resource *ptr1 = malloc(…);
if (SUCCESS == iffy_operation1_involving(ptr1)) {
    Resource *ptr2 = malloc(…);
    if (SUCCESS == iffy_operation2_involving(ptr2)) {
        …
    }
    free(ptr2);
}
free(ptr1);

但是C#有异常和自动内存管理。用这种方式编写代码没有意义了。相反,一个更重要的观察是,成功只有一种方式,但在这一过程中却有许多失败的机会。因此,最好是线性地编写代码,而不嵌套:

代码语言:javascript
复制
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;
}

请注意,“抽象数据类型”是一个非常漏洞百出的抽象。由于一切都是公开的,因此可以通过这样做来绕过所有验证:

代码语言:javascript
复制
TVMData tvm = new TVMData();
tvm.DiscountRate = -1m;
tvm.CashFlowFromAsset = -1000000m;

如果希望以该样式填充数据,则应该使用属性而不是公开公共成员。

票数 3
EN

Code Review用户

发布于 2015-02-25 12:04:11

除了两个我都同意的现有评论之外,我还怀疑为您的方法设置五个参数是否明智,特别是考虑到前四个参数是相同的类型(十进制)。我更喜欢构造一个“参数类”。

代码语言:javascript
复制
public class DataParameters
{
   public decimal DiscountRate { get; set; }
   public decimal PeriodLength { get; set; }
   // etc.
}

(请注意,DataParameters是一个坏名字,它应该是一个更有意义的名称。)

然后像这样填充该类:

代码语言:javascript
复制
var dataParameters = new DataParameters
{
   DiscountRate = discountRate;
   PeriodLength = periodLength;
   /// etc.
}

这种方式不太容易出错:如果在调用该方法时意外切换了discountRateperiodLength,该怎么办?(当然,使用命名参数可以防止这种情况发生。)

您的构造函数将变成:

代码语言:javascript
复制
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违反了微软的大写规则:“只将首字母首字母大写为三个或三个以上字符”“只将首字母首字母大写为三个或三个以上字符”

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/82546

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档