我们先想象一个类似的类:
public class Vasya
{
public void FreezeWater() => ...
public void WalkOnWater() => ...
}
也就是说,我们的Vasya可以冻结水,也可以尝试在上面行走。在冰上行走并没有什么困难,所以一个类似的假设代码:
var vasya = new Vasya();
vasya.FreezeWater();
vasya.WalkOnWater();
将毫无问题地运行,但以下块:
var vasya = new Vasya();
vasya.WalkOnWater();
会扔给我们一些VasyaDrownedException,因为他Vasya没有把水带到适合走路的聚集状态。
既然我们不想这么突然和 Vasya 说再见,我们可以像这样修补这个类:
public class Vasya
{
public bool IsWaterFrozen{ get; private set; } = false;
public void FreezeWater()
{
IsWaterFrozen = true;
...
}
public void WalkOnWater()
{
if (!IsWaterFrozen)
throw new InvalidActionException("Water is not frozen!");
...
}
}
在这种情况下,试图淹死 Vasya 的臭名昭著的尝试会抛出我们已经预料到的异常,所以我们可以到此结束,但问题是:我们的 Vasya 是一个非常鲁莽的物体,所以他在水中跑了几千次。第二。因此,我们每秒有一千个额外的检查和一千个假设的异常(我们知道,抛出异常并不是一个便宜的操作)
这种经常被调用的方法(所以它的性能很关键)的情况对我来说似乎是不可接受的。
理论上,您可以像这样解决这种情况:
public class Vasya
{
public bool IsWaterFrozen{ get; private set; } = false;
private Action _walkOnWater ;
public Vasya() => _walkOnWater = ThrowWaterIsNotFrozen;
public void FreezeWater()
{
_walkOnWater = SuccessfullyWalkOnWater;
IsWaterFrozen = true;
...
}
public void WalkOnWater() => _walkOnWater();
private void ThrowWaterIsNotFrozen() => throw new InvalidActionException("Water is not frozen!");
private void SuccessfullyWalkOnWater() => ...
}
也就是说,我们通过只更改一次调用上下文来保存方法免于不断检查
但是在这里我还有一个问题:
额外的委托调用不会比检查布尔标志更昂贵吗?
总的来说,划一条线,问题是:如何组织一个方法调用更正确,它的逻辑取决于另一个方法的调用,而且它的性能对我们来说非常非常关键
我也不知道我是否正确理解了这个问题,我会按照我的理解回答。
在我看来,有三种选择:
在第一种情况下,我们将它们封装在第三种方法中,该方法始终以正确的顺序调用它们。在这种情况下,不需要检查,也不会引发异常。
因此,如果我们想让 Vasya 走上去,那么
在第二种情况下,我们将第一种方法保持打开状态,其他一切都与第一种方法相同。
在第三种情况下,我们期望调用第二种方法,而不是先调用第一个方法。让瓦夏想走就走,水还没结冰就骂他,实在是太奇怪了。因此,在这种情况下产生的异常在我看来是不正确的。我们希望它能够在水不结冰的情况下行走,因此必须将这种情况视为正常,而不是例外。@Andrew 的回答显示了一种可能的解决方案。Vasya可以随时去散步,他决定是否去。
您可以更进一步,通过实施水的状态模式或 Vasya 的策略来摆脱每次 Vasya 采取新步骤时检查水是否结冰的问题。例如,Vasya 的策略
在 Vasya 的所有赌博中,将调用所需的方法而无需任何检查
事实上,你可以申请你的案子
State pattern。创建 Vasya 状态类型的接口
现在我们在“水未冻结”和“水已冻结”两个类中实现这个接口。
好吧,现在实际上是瓦夏本人
这种模式无疑的优点是不需要产生一堆if()来检查对象属性值的各种条件,也没有人取消对责任唯一性原则的遵守。是的,不需要抛出任何异常等等。
测试用例本身在这里。
嗯,据我理解的问题...
但我认为这是最快的方法。
在任何情况下,通过方法返回标志都比异常快,使用委托,或者,上帝禁止,从外部某处 tryCatch