此文为译文,原文地址请点击

本文通过重构一个垃圾代码,阐述了如何写出优秀的代码。开发人员及代码审核人员需按照此规范开发和审核代码。此规范以C#为例,JAVA的童鞋一并参考,C++的童鞋自行脑补吧。


简介

这篇文章的目的是展示如何将一段垃圾代码重构成一个干净的、可扩展性和可维护的代码。我将解释如何通过最佳实践和更好的设计模式来改写它。

阅读本文你需要有以下基础:

  • c# 基础
  • 依赖注入,工厂模式,策略模式

此文中的例子源于实际项目,这里不会有什么使用装饰模式构建的披萨,也不会使用策略模式的计算器,这些例子是非常好的说明,但是它们很难被在实际项目中使用。

一段垃圾代码

在我们真实的产品中有这么一个类:

public class Class1
{
public decimal Calculate(decimal amount, int type, int years)
{
decimal result = 0;
decimal disc = (years > 5) ? (decimal)5/100 : (decimal)years/100;
if (type == 1)
{
result = amount;
}
else if (type == 2)
{
result = (amount - (0.1m * amount)) - disc * (amount - (0.1m * amount));
}
else if (type == 3)
{
result = (0.7m * amount) - disc * (0.7m * amount);
}
else if (type == 4)
{
result = (amount - (0.5m * amount)) - disc * (amount - (0.5m * amount));
}
return result;
}
}

这是一段非常糟糕的代码(二胡:如果你没觉得这段代码很糟糕,那你目前状态可能很糟糕了),我们不太清楚这个类的目的是什么。它可能是一个网上商城的折扣管理类,负责为客户计算折扣。

这个类完全具备了不可读、不可维护、不可扩展的特点,它使用了很多坏的实践和反模式的设计。

下面我们逐步分析这里到底有多少问题?

  • 命名问题 - 我们只能通过猜测这个类到底是为了计算什么。这实在是在浪费时间。

    如果我们没有相关文档或者重构这段代码,那我们下一次恐怕需要花大量的时间才能知道这段代码的具体含义。

  • 魔数 - 在这个例子中,你能猜到变量type是指客户账户的状态吗。通过if-else来选择计算优惠后的产品价格。

    现在,我们压根不知道账户状态1,2,3,4分别是什么意思。

    此外,你知道0.1,0.7,0.5都是什么意思吗?

    让我们想象一下,如果你要修改下面这行代码:

    result = (amount - (0.5m * amount)) - disc * (amount - (0.5m * amount));

  • 隐藏的BUG - 因为代码非常糟糕,我们可能会错过非常重要的事情。试想一下,如果我们的系统中新增了一类账户状态,而新的账户等级不满足任何一个if-else条件。这时,返回值会固定为0。

  • 不可读 - 我们不得不承认,这是一段不可读的代码。不可读=更多的理解时间+增加产生错误的风险

  • DRY – 不要产生重复的代码

    我们可能不能一眼就找出它们,但它们确实存在。

    例如:disc *(amount - (0.1m * amount));

    同样的逻辑:

    disc *(amount - (0.5m * amount));

    这里只有一个数值不一样。如果我们无法摆脱重复的代码,我们会遇到很多问题。比如某段代码在五个地方有重复,当我们需要修改这部分逻辑时,你很可能只修改到了2至3处。

  • 单一职责原则

    这个类至少具有三个职责:

    1 选择计算算法

    2 根据账户状态计算折扣

    3 根据账户网龄计算折扣

    它违反了单一职责原则。这会带来什么风险?如果我们将要修改第三个功能的话,会影响到另外第二个功能。这就意味着,我们每次修改都会改动我们本不想修改的代码。因此,我们不得不对整个类进行测试,这实在很浪费时间。

重构

通过以下9布,我会告诉你们如何避免上述风险并实现一个干净的、可维护的、可测试的代码。

  1. 命名,命名,命名

    这是良好代码的最重要方面之一。我们只需要改变方法,参数和变量的命名。现在,我们可以确切的知道下面的类是负责什么的了。

    public decimal ApplyDiscount(decimal price, int accountStatus, int timeOfHavingAccountInYears)
    {
    decimal priceAfterDiscount = 0;
    decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5 / 100 : (decimal)timeOfHavingAccountInYears / 100;
    if (accountStatus == 1)
    {
    priceAfterDiscount = price;
    }
    else if (accountStatus == 2)
    {
    priceAfterDiscount = (price - (0.1m * price)) - (discountForLoyaltyInPercentage * (price - (0.1m * price)));
    }
    else if (accountStatus == 3)
    {
    priceAfterDiscount = (0.7m * price) - (discountForLoyaltyInPercentage * (0.7m * price));
    }
    else if (accountStatus == 4)
    {
    priceAfterDiscount = (price - (0.5m * price)) - (discountForLoyaltyInPercentage * (price - (0.5m * price)));
    } return priceAfterDiscount;
    }

但是我们任然不知道账户状态1,2,3到底是什么意思。

  1. 魔数

    在C#中避免魔数我们一般采用枚举来替换它们。这里使用AccountStatus 枚举来替换if-else中的魔数。

    public enum AccountStatus { NotRegistered = 1, SimpleCustomer = 2, ValuableCustomer = 3, MostValuableCustomer = 4 }

    现在我们来看看重构后的类,我们可以很容易的说出哪一个账户状态应该用什么算法来计算折扣。混合账户状态的风险迅速的下降了。

     public class DiscountManager
    {
    public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
    {
    decimal priceAfterDiscount = 0;
    decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5 / 100 : (decimal)timeOfHavingAccountInYears / 100; if (accountStatus == AccountStatus.NotRegistered)
    {
    priceAfterDiscount = price;
    }
    else if (accountStatus == AccountStatus.SimpleCustomer)
    {
    priceAfterDiscount = (price - (0.1m * price)) - (discountForLoyaltyInPercentage * (price - (0.1m * price)));
    }
    else if (accountStatus == AccountStatus.ValuableCustomer)
    {
    priceAfterDiscount = (0.7m * price) - (discountForLoyaltyInPercentage * (0.7m * price));
    }
    else if (accountStatus == AccountStatus.MostValuableCustomer)
    {
    priceAfterDiscount = (price - (0.5m * price)) - (discountForLoyaltyInPercentage * (price - (0.5m * price)));
    }
    return priceAfterDiscount;
    }
    }
  2. 更多的代码可读性

    在这一步中,我们使用switch-case 来替换 if-else if来增强代码可读性。

    同时,我还将某些长度很长的语句才分成两行。比如:**priceAfterDiscount = (price - (0.5m * price)) - (discountForLoyaltyInPercentage * (price - (0.5m * price)));**

    被修改为:

    **priceAfterDiscount = (price - (0.5m * price));priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);**

    以下是完整的修改:

     public class DiscountManager
    {
    public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
    {
    decimal priceAfterDiscount = 0;
    decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5 / 100 : (decimal)timeOfHavingAccountInYears / 100;
    switch (accountStatus)
    {
    case AccountStatus.NotRegistered:
    priceAfterDiscount = price;
    break;
    case AccountStatus.SimpleCustomer:
    priceAfterDiscount = (price - (0.1m * price));
    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
    break;
    case AccountStatus.ValuableCustomer:
    priceAfterDiscount = (0.7m * price);
    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
    break;
    case AccountStatus.MostValuableCustomer:
    priceAfterDiscount = (price - (0.5m * price));
    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
    break;
    }
    return priceAfterDiscount;
    }
    }
  3. 消除隐藏的BUG

    正如我们之前提到的,我们的ApplyDiscount方法可能将为新的客户状态返回0。

    我们怎样才能解决这个问题?答案就是抛出NotImplementedException。

    当我们的方法获取账户状态作为输入参数,但是参数值可能包含我们未设计到的未知情况。这时,我们不能什么也不做,抛出异常是这时候最好的做法。

        public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
    {
    decimal priceAfterDiscount = 0;
    decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5 / 100 : (decimal)timeOfHavingAccountInYears / 100;
    switch (accountStatus)
    {
    case AccountStatus.NotRegistered:
    priceAfterDiscount = price;
    break;
    case AccountStatus.SimpleCustomer:
    priceAfterDiscount = (price - (0.1m * price));
    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
    break;
    case AccountStatus.ValuableCustomer:
    priceAfterDiscount = (0.7m * price);
    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
    break;
    case AccountStatus.MostValuableCustomer:
    priceAfterDiscount = (price - (0.5m * price));
    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
    break;
    default:
    throw new NotImplementedException();
    }
    return priceAfterDiscount;
    }
  4. 分析算法

    在这个例子中,我们通过两个标准来计算客户折扣:

  • 账户状态

  • 账户网龄

    通过网龄计算的算法都类似这样:

    (discountForLoyaltyInPercentage * priceAfterDiscount)

    但是对于账户状态为ValuableCustomer的算法却是:

    0.7m * price

    我们把它修改成和其他账户状态一样的算法:

    price - (0.3m * price)

          public class DiscountManager
    {
    public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
    {
    decimal priceAfterDiscount = 0;
    decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5 / 100 : (decimal)timeOfHavingAccountInYears / 100;
    switch (accountStatus)
    {
    case AccountStatus.NotRegistered:
    priceAfterDiscount = price;
    break;
    case AccountStatus.SimpleCustomer:
    priceAfterDiscount = (price - (0.1m * price));
    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
    break;
    case AccountStatus.ValuableCustomer:
    priceAfterDiscount = (price - (0.3m * price));
    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
    break;
    case AccountStatus.MostValuableCustomer:
    priceAfterDiscount = (price - (0.5m * price));
    priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
    break;
    default:
    throw new NotImplementedException();
    }
    return priceAfterDiscount;
    }
    }
  1. 消除魔数的另一种方法

    使用静态常量来替换魔数。0.1m,0.2m,0.3m,我m,我们并不知道它们是什么意思。

    此外decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > 5) ? (decimal)5/100 : (decimal)timeOfHavingAccountInYears/100;中,数字5也非常神秘。

    我们必须让它们更具有描述性,这时使用常量会是一个比较好的办法。

    我们来定义一个静态类:

     public static class Constants
    {
    public const int MAXIMUM_DISCOUNT_FOR_LOYALTY = 5;
    public const decimal DISCOUNT_FOR_SIMPLE_CUSTOMERS = 0.1m;
    public const decimal DISCOUNT_FOR_VALUABLE_CUSTOMERS = 0.3m;
    public const decimal DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS = 0.5m;
    }

接着修改DiscountManager类:

    public class DiscountManager
{
public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
{
decimal priceAfterDiscount = 0;
decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY) ? (decimal)Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY / 100 : (decimal)timeOfHavingAccountInYears / 100;
switch (accountStatus)
{
case AccountStatus.NotRegistered:
priceAfterDiscount = price;
break;
case AccountStatus.SimpleCustomer:
priceAfterDiscount = (price - (Constants.DISCOUNT_FOR_SIMPLE_CUSTOMERS * price));
priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
break;
case AccountStatus.ValuableCustomer:
priceAfterDiscount = (price - (Constants.DISCOUNT_FOR_VALUABLE_CUSTOMERS * price));
priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
break;
case AccountStatus.MostValuableCustomer:
priceAfterDiscount = (price - (Constants.DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS * price));
priceAfterDiscount = priceAfterDiscount - (discountForLoyaltyInPercentage * priceAfterDiscount);
break;
default:
throw new NotImplementedException();
}
return priceAfterDiscount;
}
}
  1. 消除重复的代码

    为了消除重复的代码,这里将部分算法提取出来。首先,我们建立两个扩展方法:

     public static class PriceExtensions
    {
    public static decimal ApplyDiscountForAccountStatus(this decimal price, decimal discountSize)
    {
    return price - (discountSize * price);
    } public static decimal ApplyDiscountForTimeOfHavingAccount(this decimal price, int timeOfHavingAccountInYears)
    {
    decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY) ? (decimal)Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY / 100 : (decimal)timeOfHavingAccountInYears / 100;
    return price - (discountForLoyaltyInPercentage * price);
    }
    }

通过方法名称,我们就可以知道它的职责是什么,现在修改我们的例子:

    public class DiscountManager
{
public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
{
decimal priceAfterDiscount = 0;
switch (accountStatus)
{
case AccountStatus.NotRegistered:
priceAfterDiscount = price;
break;
case AccountStatus.SimpleCustomer:
priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_SIMPLE_CUSTOMERS)
.ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears);
break;
case AccountStatus.ValuableCustomer:
priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_VALUABLE_CUSTOMERS)
.ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears);
break;
case AccountStatus.MostValuableCustomer:
priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS)
.ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears);
break;
default:
throw new NotImplementedException();
}
return priceAfterDiscount;
}
}
  1. 删除没用的代码

    我们应该写出简短的代码,因为简短的代码=减少BUG发生的机率,并且也让我们缩短理解业务逻辑的时间。

    我们发现,这里三种状态的客户调用了相同的方法:

    .ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears);

    这里可以合并代码:

     public class DiscountManager
    {
    public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
    {
    decimal priceAfterDiscount = 0;
    switch (accountStatus)
    {
    case AccountStatus.NotRegistered:
    priceAfterDiscount = price;
    break;
    case AccountStatus.SimpleCustomer:
    priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_SIMPLE_CUSTOMERS);
    break;
    case AccountStatus.ValuableCustomer:
    priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_VALUABLE_CUSTOMERS);
    break;
    case AccountStatus.MostValuableCustomer:
    priceAfterDiscount = price.ApplyDiscountForAccountStatus(Constants.DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS);
    break;
    default:
    throw new NotImplementedException();
    }
    priceAfterDiscount = priceAfterDiscount.ApplyDiscountForTimeOfHavingAccount(timeOfHavingAccountInYears);
    return priceAfterDiscount;
    }
    }

9.最后,得到干净的代码

最后,让我们通过引入依赖注入和工厂方法模式来得到最终的版本吧。

先来看卡最终结果:

    public class DiscountManager
{
private readonly IAccountDiscountCalculatorFactory _factory;
private readonly ILoyaltyDiscountCalculator _loyaltyDiscountCalculator; public DiscountManager(IAccountDiscountCalculatorFactory factory, ILoyaltyDiscountCalculator loyaltyDiscountCalculator)
{
_factory = factory;
_loyaltyDiscountCalculator = loyaltyDiscountCalculator;
} public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
{
decimal priceAfterDiscount = 0;
priceAfterDiscount = _factory.GetAccountDiscountCalculator(accountStatus).ApplyDiscount(price);
priceAfterDiscount = _loyaltyDiscountCalculator.ApplyDiscount(priceAfterDiscount, timeOfHavingAccountInYears);
return priceAfterDiscount;
}
} public interface ILoyaltyDiscountCalculator
{
decimal ApplyDiscount(decimal price, int timeOfHavingAccountInYears);
} public class DefaultLoyaltyDiscountCalculator : ILoyaltyDiscountCalculator
{
public decimal ApplyDiscount(decimal price, int timeOfHavingAccountInYears)
{
decimal discountForLoyaltyInPercentage = (timeOfHavingAccountInYears > Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY) ? (decimal)Constants.MAXIMUM_DISCOUNT_FOR_LOYALTY / 100 : (decimal)timeOfHavingAccountInYears / 100;
return price - (discountForLoyaltyInPercentage * price);
}
} public interface IAccountDiscountCalculatorFactory
{
IAccountDiscountCalculator GetAccountDiscountCalculator(AccountStatus accountStatus);
} public class DefaultAccountDiscountCalculatorFactory : IAccountDiscountCalculatorFactory
{
public IAccountDiscountCalculator GetAccountDiscountCalculator(AccountStatus accountStatus)
{
IAccountDiscountCalculator calculator;
switch (accountStatus)
{
case AccountStatus.NotRegistered:
calculator = new NotRegisteredDiscountCalculator();
break;
case AccountStatus.SimpleCustomer:
calculator = new SimpleCustomerDiscountCalculator();
break;
case AccountStatus.ValuableCustomer:
calculator = new ValuableCustomerDiscountCalculator();
break;
case AccountStatus.MostValuableCustomer:
calculator = new MostValuableCustomerDiscountCalculator();
break;
default:
throw new NotImplementedException();
} return calculator;
}
} public interface IAccountDiscountCalculator
{
decimal ApplyDiscount(decimal price);
} public class NotRegisteredDiscountCalculator : IAccountDiscountCalculator
{
public decimal ApplyDiscount(decimal price)
{
return price;
}
} public class SimpleCustomerDiscountCalculator : IAccountDiscountCalculator
{
public decimal ApplyDiscount(decimal price)
{
return price - (Constants.DISCOUNT_FOR_SIMPLE_CUSTOMERS * price);
}
} public class ValuableCustomerDiscountCalculator : IAccountDiscountCalculator
{
public decimal ApplyDiscount(decimal price)
{
return price - (Constants.DISCOUNT_FOR_VALUABLE_CUSTOMERS * price);
}
} public class MostValuableCustomerDiscountCalculator : IAccountDiscountCalculator
{
public decimal ApplyDiscount(decimal price)
{
return price - (Constants.DISCOUNT_FOR_MOST_VALUABLE_CUSTOMERS * price);
}
}

首先,我们摆脱了扩展方法(静态类),如果我们想对ApplyDiscount方法进行单元测试是比较困难的,废除我们对PriceExtensions扩展类也进行测试。

为了避免这个问题,我们创建了DefaultLoyaltyDiscountCalculator 类来替换ApplyDiscountForTimeOfHavingAccount这个扩展方法,此类还实现了ILoyaltyDiscountCalculator接口。现在,当我们要测试DiscountManager类时,我们只构造函数注入ILoyaltyDiscountCalculator接口的实现即可。这里使用了依赖注入。

通过这样做,我们将网龄折扣的算法迁移到类似DefaultLoyaltyDiscountCalculator 的不同类中,这样当我们修改某一个算法不会覆盖到其他业务。

对于根据账户状态来计算折扣的业务,我们需要在
DiscountManager
中删除两个职责:

  • 根据账户状态选择计算的算法

  • 实现计算算法

    这里我们通过DefaultAccountDiscountCalculatorFactory工厂类来解决这个问题,DefaultAccountDiscountCalculatorFactory工厂类实现了IAccountDiscountCalculatorFactory接口。

    我们的工厂将决定选择哪一个折扣算法。接着,工厂类被通过构造函数注入到DiscountManager类中。

    下面我只需要在DiscountManager 中使用工厂:

    priceAfterDiscount = _factory.GetAccountDiscountCalculator(accountStatus).ApplyDiscount(price);

    以上,我们解决了第一个问题,下面我们需要实现计算算法。根据账户状态,提供不同的算法,这正好符合策略模式。我们需要构建三个策略:
    NotRegisteredDiscountCalculator,SimpleCustomerDiscountCalculator,MostValuableCustomerDiscountCalculator
    已经抽象出来的接口IAccountDiscountCalculator

    好了,现在我们有可一段干净可读的代码了,这段代码中所有的类都只有一个职责:

  • DiscountManager - 管理

  • DefaultLoyaltyDiscountCalculator - 网龄计算折扣

  • DefaultAccountDiscountCalculatorFactory - 根据账户状态选择折扣策略

  • NotRegisteredDiscountCalculator,SimpleCustomerDiscountCalculator,MostValuableCustomerDiscountCalculator-计算折扣算法

    我们来比较一下修改前后的代码:

      public class Class1
    {
    public decimal Calculate(decimal amount, int type, int years)
    {
    decimal result = 0;
    decimal disc = (years > 5) ? (decimal)5 / 100 : (decimal)years / 100;
    if (type == 1)
    {
    result = amount;
    }
    else if (type == 2)
    {
    result = (amount - (0.1m * amount)) - disc * (amount - (0.1m * amount));
    }
    else if (type == 3)
    {
    result = (0.7m * amount) - disc * (0.7m * amount);
    }
    else if (type == 4)
    {
    result = (amount - (0.5m * amount)) - disc * (amount - (0.5m * amount));
    }
    return result;
    }
    }

修改后:

    public class DiscountManager
{
private readonly IAccountDiscountCalculatorFactory _factory;
private readonly ILoyaltyDiscountCalculator _loyaltyDiscountCalculator; public DiscountManager(IAccountDiscountCalculatorFactory factory, ILoyaltyDiscountCalculator loyaltyDiscountCalculator)
{
_factory = factory;
_loyaltyDiscountCalculator = loyaltyDiscountCalculator;
} public decimal ApplyDiscount(decimal price, AccountStatus accountStatus, int timeOfHavingAccountInYears)
{
decimal priceAfterDiscount = 0;
priceAfterDiscount = _factory.GetAccountDiscountCalculator(accountStatus).ApplyDiscount(price);
priceAfterDiscount = _loyaltyDiscountCalculator.ApplyDiscount(priceAfterDiscount, timeOfHavingAccountInYears);
return priceAfterDiscount;
}
}

总结

本文通过简单易懂的方法重构了一段问题代码,它显示了如何在实际情况中使用最佳实践和设计模式来帮助我们写出干净的代码。

就我的工作经验来说,本文中出现的不良做法是经常发生的。编写这种代码的人总是认为他们能够保持这种规则,但不幸的是系统和业务往往都会越来越复杂,每次修改这类代码时都会带来巨大的风险。

拿什么拯救你,我的代码--c#编码规范实战篇的更多相关文章

  1. 拿什么拯救你,我的代码--c#编码规范实战篇 (转)

    http://www.cnblogs.com/lazio10000/p/5413439.html 此文为译文,原文地址请点击. 本文通过重构一个垃圾代码,阐述了如何写出优秀的代码.开发人员及代码审核人 ...

  2. Discuz代码研究-编码规范

    Discuz中的编码规范很值得PHP开发人员借鉴.里面既介绍了编码时代码标记,注释,书写规则,命名原则等方面基础的内容,对代码的安全性,性能,兼容性,代码重用,数据库设计,数据库性能及优化作了阐述,这 ...

  3. Delphi与字符编码(实战篇)(MultiByteToWideChar会返回转换后的宽字符串长度)

    本文目标: 了解Delphi的字符串类型 字符编码的检测与转换 简体繁体转换 0. 导言 看完“.Net与字符编码(理论篇)”,我们明白了字符是自然语言中的最小单位,在存储和传输的过程中可以使用三种编 ...

  4. 前端编码规范 -- css篇

    合理的避免使用ID 一般情况下ID不应该被应用于样式. ID的样式不能被复用并且每个页面中你只能使用一次ID. 使用ID唯一有效的是确定网页或整个站点中的位置. 尽管如此,你应该始终考虑使用class ...

  5. 前端编码规范 -- html篇

    文档类型 推荐使用 HTML5 的文档类型申明: <!DOCTYPE html> (建议使用 text/html 格式的 HTML.避免使用 XHTML.XHTML 以及它的属性,比如 a ...

  6. raywenderlich.com Objective-C编码规范

    原文链接 : The official raywenderlich.com Objective-C style guide 原文作者 : raywenderlich.com Team 译文出自 : r ...

  7. Ray Wenderlich 的 Objective-C编码规范

    由于我正在准备模仿饿了么这个app,到时可能有些iOS开发者参与进来.这时如果每个人的Objective-C编码风格都不一样,这样不易于保持代码一致性和难以Code Review.所以我在网上搜索到  ...

  8. Objective-C编码规范[译]

    原文链接 : The official raywenderlich.com Objective-C style guide 原文作者 : raywenderlich.com Team 译文出自 : r ...

  9. JAVA_SE基础——编码规范&代码编写规则

    这次我来给大家说明下编码规范&代码编写规则  ↓ 编码规范可以帮助程序员在编程时注意一些细节问题,提高程序的可读性,让程序员能够尽快地理解新的代码,并帮助大家编写出规范的利于维护的Java代码 ...

随机推荐

  1. js中constructor和prototype

    在最开始学习js的时候,我们在讲到原型链和构造函数的时候经常会有一个例子 如果我们定义函数如下: function Foo() { /* .. */ } Foo.prototype.bar = fun ...

  2. 【模块化编程】理解requireJS-实现一个简单的模块加载器

    在前文中我们不止一次强调过模块化编程的重要性,以及其可以解决的问题: ① 解决单文件变量命名冲突问题 ② 解决前端多人协作问题 ③ 解决文件依赖问题 ④ 按需加载(这个说法其实很假了) ⑤ ..... ...

  3. browserify学习总结

    前言 在未接触browserify,虽然我知道它是一个前端构建工具,但还是有几个疑问: 1. browserify出现的日期? 2. 能构建哪些文件? 3. 附加的browserify代码体积是多大? ...

  4. JavsScript+dom

    JavsScript+dom DOM(兼容性) 用于操作文档树 1.帮助我们找到标签 直接查找 间接查找 getElementById getElementsByTageName 2.标签操作 内容: ...

  5. CSS3-02 样式 1

    概述 上一篇博客中,概述了如何在 HTML 文档中使用 CSS,以及如何选择 HTML 元素,并且在文档的最后以表格的形式给出了 CSS 中所有的属性.在接下来的这篇博客中,将阐述主要 HTML 元素 ...

  6. Linux mysql 5.6: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

    案例环境: 操作系统 :Red Hat Enterprise Linux Server release 5.7 (Tikanga) 64 bit 数据库版本 : Mysql 5.6.19 64 bit ...

  7. 记一次Linux服务器上查杀木马经历

    开篇前言 Linux服务器一直给我们的印象是安全.稳定.可靠,性能卓越.由于一来Linux本身的安全机制,Linux上的病毒.木马较少,二则由于宣称Linux是最安全的操作系统,导致很多人对Linux ...

  8. TCP Provider The semaphore timeout period has expired

    我们一数据库服务器上有个作业最近几天偶尔会遇到下面错误(敏感信息已做处理),主要是报"TCP Provider: The semaphore timeout period has expir ...

  9. webForm(三)——三级联动

    三级联动 首先附图一张,初步认识一下什么是三级联动:                           注:选第一个后面两个变,选第二个,最后一个改变. 其次,做三级联动需要注意的方面:①DropD ...

  10. [AlwaysOn Availability Groups]AlwaysOn等待类型

    AlwaysOn等待类型 当排查AlwaysOn延迟,等待统计信息可以在DMV中查看累计的AlwaysOn等待类型. 查看AlwaysOn等待类型 SELECT * FROM sys.dm_os_wa ...