几乎每位开发人员都曾遇到过这样的情况:一个复杂的算法被写在一个几乎无法阅读的方法中,并且与类中的其他方法纠缠在一起。 例如,假设您有一个用于求解方程的通用类:
public class EquationSolvers
{
public static Tuple<double, double> Quadratic(double a, double b, double c)
{
double disc = b*b - 4*a*c;
if (disc < 0)
throw new ArgumentException("Cannot solve equation with complex roots");
double sqrt = Math.Sqrt(disc);
return new Tuple<double, double>(
(-b + sqrt) / (2 * a), (-b - sqrt) / (2 * a));
}
// other solvers here
}
上述方程求解器是硬编码的,这意味着如果要替换为不同的求解器,您必须手动替换每个实例。 让我们先将其提取到一个单独的类中。 为此,我们使用 移动到另一类型的重构 F6 :
然后,我们需要指定要将方法移动到的类。 为了更好地分离关注点,我们选择一个名为 QuadraticEquationSolver 的单独类:
现在方法已经被移动了,让我们尝试将判别式提取到一个单独的计算中。 这很简单——我们选择判别式计算并调用 提取方法重构 Control+Alt+M :
现在,我们需要做的就是给新方法命名:
完成了:
private static double CalculateDiscriminant(double a, double b, double c)
{
return b * b - 4 * a * c;
}
现在,假设过了一段时间,我们找到了一个更安全的二次方程求解器。 为了将其引入程序,我们首先需要创建一个抽象基类 QuadraticEquationSolverBase。 我们使用 提取超类重构 重构功能,该功能可在 重构 菜单 Control+Shift+R 中找到:
在显示的对话框中,我们可以选择哪些成员将被向上提升。 我们只需要 CalculateDiscriminant 方法:
我们添加了 Calculate() 方法的抽象定义(之前称为 Quadratic() ),并得到了以下基类:
public abstract class QuadraticEquationSolverBase
{
protected double CalculateDiscriminant(double a, double b, double c)
{
return b*b - 4*a*c;
}
public abstract Tuple<double, double> Calculate(double a, double b, double c);
}
我们还移除了代码中任何地方的 静态 关键字,假设 QuadraticEquationSolverBase 的实现将由代码中的生命周期管理器处理。 因此,ReSharper 提醒我们在 QuadraticEquationSolver 类中为重命名的 计算 方法添加 重写 关键字:
现在,假设我们找到了一个更安全版本的二次方程求解器。 让我们实现它。 首先,我们在基类上使用 创建派生类型 context action :
然后,我们被要求在此类型上实现成员,我们照做了:
最后,我们提供了一个实现,利用了基类的 CalculateDiscriminant() 方法:
class SafeQuadraticEquationSolver : QuadraticEquationSolverBase
{
public override Tuple<double, double> Calculate(double a, double b, double c)
{
double disc = CalculateDiscriminant(a, b, c);
if (disc < 0)
throw new ArgumentException("Cannot solve equation with complex roots");
double q = -0.5*(b + Math.Sign(b)*disc);
return new Tuple<double, double> (q/a, c/q);
}
}
完成了! 现在,二次方程求解器可以轻松使用,其配置和实例化通常由 IoC 容器处理。
最后修改日期: 2025年 9月 27日