在我的 class 中摆脱重复 if 语句的建议

Advice to get rid of repeating if statement in my class

我最近在工作中遇到一段代码,它有一个重复的 if-else 条件,用于检查名为 OperationType 的枚举:

public enum OperationType
{ A, B }

现在 class 的工作是 运行 在设备 A 或设备 B 上进行操作,同时从 SharedDevice 读取并存储一些值,基本上用于X,Y 图。我们在DeviceA或DeviceB的函数中记录SharedDevice的特性。问题是我们需要遍历不同参数的列表并将它们发送到 SharedDevice。此列表对于设备 A 和设备 B 是不同的。

Device class:

public class Device
{
    public double CurrentValue { get; }
    public DeviceParameters Parameters { get; set; }
}

这里是负责执行此操作的class:

public class MyOperationExecuter
{
    public Device SharedDevice { get; }
    public Device DeviceA { get; }
    public Device DeviceB { get; }

    public List<DeviceParameters> ParametersA { get; }
    public List<DeviceParameters> ParametersB { get; }

    public List<double> XValuesOfA { get; }
    public List<double> YValuesOfA { get; }
    public List<double> XValuesOfB { get; }
    public List<double> YValuesOfB { get; }

    public void DoMyOperation(OperationType operationType)
    {
        List<DeviceParameters> changingDeviceParameters;

        if (operationType == OperationType.A)
        {
            changingDeviceParameters = ParametersA;
        }
        else
        {
            changingDeviceParameters = ParametersB;
        }

        if (operationType == OperationType.A)
        {
            XValuesOfA.Clear();
            YValuesOfA.Clear();
        }
        else
        {
            XValuesOfB.Clear();
            YValuesOfB.Clear();
        }

        foreach (var parameters in changingDeviceParameters)
        {
            // set the device parameters
            SharedDevice.Parameters = parameters;

            // retrieve the device readings and store the values in the correct dataprovider
            if (operationType == OperationType.A)
            {
                XValuesOfA.Add(DeviceA.CurrentValue);
                YValuesOfA.Add(SharedDevice.CurrentValue));
            }
            else
            {
                XValuesOfB.Add(DeviceB.CurrentValue);
                YValuesOfB.Add(SharedDevice.CurrentValue);
            }
        }

        // save updated x,y data
        Save();
    }
}

如您所见,有一个重复的 if 语句,这不是未来的证据,因为我们必须在每一步中检查枚举。此外,我们可能需要添加一个 C 型设备,这将导致不断增长的 switch 语句。我们可能还需要对 A 和 B 执行操作。我应该如何重构这个操作,以便我可以继续扩展它,而不必总是重复 if-else 逻辑?

一个相当简单的方法是声明一个代表 A 或 B 的变量:

var XValues = operationType == OperationType.A ? XValuesOfA : XValuesOfB;

那么你就可以使用 XValues 了。对 DeviceA 执行相同的操作。如果你有更多的操作,你可以使用 switch expression.

一个更简洁的解决方案是制作包含 A 或 B 所需的所有内容的单独对象,这样您的 class 可以简单地检查操作类型,然后将所有工作委托给相应的对象。即

public class MyDevice
{
    public Device SharedDevice { get; }
    public Device Device { get; }

    public List<DeviceParameters> Parameters { get; }

    public List<double> XValuesOf { get; }
    public List<double> YValuesOf { get; }

    public void DoMyOperation()
    {
    ...
    }
}

我还建议使用包含 X 和 Y 值的单个列表,例如 Vector2。我发现这更容易使用,并且有助于避免重复代码。

您应该添加新的 class。这将用于定义设备类型特定的属性。

一个class这样的;

public class MyDeviceValues
{
    public MyDeviceValues(List<DeviceParameters> parameters, List<double> xValuesOf, List<double> yValuesOf)
    {
        Parameters = parameters;
        XValues = xValuesOf;
        YValues = yValuesOf;
    }

    public List<DeviceParameters> Parameters { get; }

    public List<double> XValues { get; }

    public List<double> YValues { get; }
}

因此,您可以拥有一个通用的 DoMyOperation 函数。它将是这样的:

public void DoMyOperation(MyDeviceValues myDeviceValues)
{
    var changingDeviceParameters = myDeviceValues.Parameters;

    myDeviceValues.XValues.Clear();
    myDeviceValues.YValues.Clear();

    foreach (var parameters in changingDeviceParameters)
    {
        // set the device parameters
        SharedDevice.Parameters = parameters;

        // retrieve the device readings and store the values in the correct dataprovider
        myDeviceValues.XValues.Add(DeviceA.CurrentValue);
        myDeviceValues.YValues.Add(SharedDevice.CurrentValue);
    }

    // save updated x,y data
    Save();
}

这是您粘贴的整个代码的重构版本:

https://dotnetfiddle.net/dLyJl9

不改变 class fields/properties 我会采用新方法:

private void SetParameters(List<DeviceParameters> parameters, List<double> xValues, List<double> yValues, Device device)
{
    xValues.Clear();
    yValues.Clear();
    foreach(var parameter in parameters)
    {
        SharedDevice.Parameters = parameter;
        xValues.Add(device.CurrentValue);
        yValues.Add(SharedDevice.CurrentValue);
    }
}

然后在 DoMyOperation 中足以:

if (operationType == OperationType.A)
{
    SetParameter(ParametersA, XValuesOfA, YValuesOfA, DeviceA);
}
else
{
    SetParameter(ParametersB, XValuesOfB, YValuesOfB, DeviceB);
}