重构if-else if - else

Ale*_*lex 13 c# refactoring design-patterns if-statement solid-principles

我有以下代码示例

if(object.Time > 0 && <= 499)
{
     rate = .75m
}
else if(object.Time >= 500 && <= 999)
{
     rate = .85m
}
else if(object.Time >= 1000)
{
     rate = 1.00m
}
else
{
     rate = 0m;
}
Run Code Online (Sandbox Code Playgroud)

我的问题是我可以用什么设计模式来改善它?

编辑:为了更清楚地说明,您在此处看到的代码是战略模式实施中当前存在的内容.我们有3种类型的计算,其中2种具有3种不同的"费率",可以根据您在下面看到的时间使用.我考虑过为每个速率创建一个策略实现,但后来我会移动逻辑来确定使用的策略并使其变得混乱.

谢谢!

Pie*_*ult 20

如果您真的在寻找设计模式,我会选择责任链模式.

基本上你的"链接"试图处理输入.如果它无法处理它,它会传递到链中,直到另一个链接可以处理它.如果您有单元测试,还可以在单​​元测试中定义一个易于模拟的界面.

所以你有这个抽象类,每个链接都将继承:

public abstract class Link
{
    private Link nextLink;

    public void SetSuccessor(Link next)
    {
        nextLink = next;
    }

    public virtual decimal Execute(int time)
    {
        if (nextLink != null)
        {
            return nextLink.Execute(time);
        }
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用您的规则创建每个链接:

public class FirstLink : Link
{
    public override decimal Execute(int time)
    {
        if (time > 0 && time <= 499)
        {
            return .75m;
        }

        return base.Execute(time);
    }
}

public class SecondLink : Link
{
    public override decimal Execute(int time)
    {
        if (time > 500 && time <= 999)
        {
            return .85m;
        }

        return base.Execute(time);
    }
}

public class ThirdLink : Link
{
    public override decimal Execute(int time)
    {
        if (time >= 1000)
        {
            return 1.00m;
        }

        return base.Execute(time);
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,要使用它,只需设置每个后继并调用它:

Link chain = new FirstLink();
Link secondLink = new SecondLink();
Link thirdLink = new ThirdLink();


chain.SetSuccessor(secondLink);
secondLink.SetSuccessor(thirdLink);
Run Code Online (Sandbox Code Playgroud)

而你所要做的就是通过一个干净的电话打电话给连锁店:

var result = chain.Execute(object.Time);
Run Code Online (Sandbox Code Playgroud)


123*_*9 0 10

有一种不那么着名的模式称为" 规则模式 "

我们的想法是将所有内容提取到一个对象中,然后让它处理自己的工作.您定义的每个规则的每个类都是您的条件语句,例如(object.Time> 0 && <= 499)

public class RuleNumberOne : IRules
{
   public decimal Execute(Oobject date)
   {
      if(date.Time > 0 && date.Something <= 499)
         return .75m;
      return 0;
   } 
} 

public class RuleNumberTwo : IRules
{
    public decimal Execute(Oobject date)
    {
        if(date.Time >= 500 && date.Something <= 999)
            return .85m;
        return 0;
    } 
} 

public interface IRules
{ 
  decimal Execute(Oobject date);
}
Run Code Online (Sandbox Code Playgroud)

因此,在你的课上看起来像这样

if(object.Time > 0 && <= 499)
{
     rate = .75m
}
else if(object.Time >= 500 && <= 999)
{
     rate = .85m
}
else if(object.Time >= 1000)
{
     rate = 1.00m
}
else
{
     rate = 0m;
}
Run Code Online (Sandbox Code Playgroud)

现在会,

private List<IRules>_rules = new List<IRules>();
public SomeConstructor()
{
    _rules.Add(new RuleNumberOne());
    _rules.Add(new RuleNumberTwo());
}

public void DoSomething()
{

    Oobject date = new Oobject();

    foreach(var rule in this._rules)
    {
        Decimal rate = rule.Execute(date);
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的想法是,一旦你在条件中嵌套,就会更难阅读条件语句,开发人员很难做出任何改变.因此,它将每个单独规则的逻辑及其效果分离为遵循规则单一责任模式的自己的类.

一些注意事项是 1.)只读2.)显式顺序3.)依赖性4.)优先级5.)持久性

同样,当您有越来越多的条件复杂性并且您的应用程序的要求需要时,请考虑使用规则模式.

你可以自定义它,如果你不想让它返回小数或其他东西,但想法就在这里.

  • 策略模式与规则模式不同. (2认同)

cHa*_*Hao 5

您只需要检查范围的一个端点.另一个是由你实际存在于代码中的那一点暗示的,因为早期的条件是错误的.

if (obj.Time <= 0) {
    rate = 0.00m;
}

// At this point, obj.Time already must be >= 0, because the test
// to see if it was <= 0 returned false.
else if (obj.Time < 500) {
    rate = 0.75m;
}

// And at this point, obj.Time already must be >= 500.
else if (obj.Time < 1000) { 
    rate = 0.85m;
}

else {
    rate = 1.00m;
}
Run Code Online (Sandbox Code Playgroud)

出于可读性和性能原因,最好将比例尺更常见的结果放在首先检查的那一端.但无论哪种方式都可以.

  • +1,这就是我要发布的内容,但是我建议的另一个更改是将开头的`obj.Time`的结果缓存到局部变量并检查.如果`obj.Time`是一个大型结构或具有昂贵成本的属性,它可以提高性能.(如果Time是一个像'DateTime.Now`这样的变化属性,你可以在迭代'if`语句时跨越边界) (2认同)