重构使代码对扩展开放,但对修改不开放

问题描述 投票:0回答:1

出于我的项目目的,我需要将指标发送到AWS。

我有一个叫做SendingMetrics的主类。

private CPUMetric _cpuMetric;
private RAMMetric _ramMetric;
private HDDMetric _hddMetric;
private CloudWatchClient _cloudWatchClient(); //AWS Client which contains method Send() that sends metrics to AWS

public SendingMetrics()
{
    _cpuMetric = new CPUMetric();
    _ramMetric = new RAMMetric();
    _hddMetric = new HDDMetric();
    _cloudwatchClient = new CloudwatchClient();
    InitializeTimer();
}

private void InitializeTimer()
{
   //here I initialize Timer object which will call method SendMetrics() each 60 seconds.
}

private void SendMetrics()
{
    SendCPUMetric();
    SendRAMMetric();
    SendHDDMetric();
}

private void SendCPUMetric()
{
    _cloudwatchClient.Send("CPU_Metric", _cpuMetric.GetValue());
}

private void SendRAMMetric()
{
    _cloudwatchClient.Send("RAM_Metric", _ramMetric.GetValue());
}

private void SendHDDMetric()
{
    _cloudwatchClient.Send("HDD_Metric", _hddMetric.GetValue());
}

此外,我还有看起来非常相似的CPUMetric,RAMMetric和HDDMetric类,所以我只显示一个类的代码。

internal sealed class CPUMetric
{
    private int _cpuThreshold;

    public CPUMetric()
    {
        _cpuThreshold = 95;
    }

    public int GetValue()
    {
        var currentCpuLoad = ... //logic for getting machine CPU load
        if(currentCpuLoad > _cpuThreshold)
        {
             return 1;
        }
        else 
        {
             return 0;
        }
    }
}

所以我的问题是在我的示例中不满足干净的编码。我要发送3个指标,如果需要引入新指标,则需要创建新类,在SendingMetrics类中对其进行初始化并修改该类,这不是我想要的。我想满足开放封闭原则,因此它可以扩展,但可以修改。

正确的方法是什么?我会将那些发送方法(SendCPUMetric,SendRAMMetric,SendHDDMetric)移到相应的类(将SendCPUMetric方法移至CPUMetric类,将SendRAMMEtric移至RAMMetric等),但是如何修改SendingMetrics类,以便对它进行修改以及是否需要向其添加新度量标准而关闭不改变那个阶级。

c# coding-style solid-principles open-closed-principle
1个回答
0
投票

您的设计几乎是正确的。您有3个数据检索器和1个数据发送器。因此,在不影响当前指标的情况下(增加修改即可)添加更多指标(更多检索器)(对扩展开放)很容易,您只需要多一点重构即可减少重复的代码。

而不是拥有3个指标类,它们看起来非常相似。仅下一行不同

var currentCpuLoad = ... //logic for getting machine CPU load

您可以创建这样的通用指标

internal interface IGetMetric
{
    int GetData();
}

internal sealed class Metric
{
    private int _threshold;
    private IGetMetric _getDataService;

    public Metric(IGetMetric getDataService)
    {
        _cpuThreshold = 95;
        _getDataService = getDataService;
    }

    public int GetValue()
    {
        var currentCpuLoad = _getDataService.GetData();
        if(currentCpuLoad > _cpuThreshold)
        {
             return 1;
        }
        else 
        {
             return 0;
        }
    }
}

然后只需创建3个GetMetric类来实现该接口。这只是减少代码重复的一种方法。您也可以使用继承(但我不喜欢继承)。或者,您可以使用Func参数。

更新:添加了类以获取CPU指标

internal class CPUMetricService : IGetMetric
{
    public int GetData() { return ....; }
}
internal class RAMMetricService : IGetMetric
{
    public int GetData() { return ....; }
}
public class AllMetrics
{
    private List<Metric> _metrics = new List<Metric>()
    {
         new Metric(new CPUMetricService());
         new Metric(new RAMMetricService());
    }

    public void SendMetrics()
    {
         _metrics.ForEach(m => ....);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.