这个构造函数是否违反了单一职责原则?

Is this constructor violating the Single Responsibility Principle?

我试图强迫自己使用 SOLID 原则并编写可单元测试的代码。最近在写代码的时候变得偏执和优柔寡断,总觉得自己总是在违背一些原则。

考虑下面的 class。 JavascriptPropertyInitializer 负责检测给定 class 中具有特殊属性的属性列表,并渲染一些 javaScript 代码。它有太多的责任吗?构造函数是不是做的太多了?

我知道我正在构造函数中实例化一个字典,而且我知道实例化具体对象是一种已知的违规行为。是的,我知道,我应该通过构造函数注入它,但为什么呢?我的class依赖具体字典有什么害处?

public class JavascriptPropertyInitializer
{
    private readonly HtmlTextWriter _writer;
    private readonly object _containerObject;
    private readonly string _javascriptObjectName;
    private readonly Dictionary<string, string> _settings;
    private List<PropertyInfo> _customWebControls;

    public JavascriptPropertyInitializer(HtmlTextWriter writer, object containerObject, string javascriptObjectName)
    {
        _writer = writer;
        _containerObject = containerObject;
        _javascriptObjectName = javascriptObjectName;
        _settings = new Dictionary<string, string>();
        ValidateParameters(writer, containerObject, javascriptObjectName);
        DetectCustomWebControls();
        CollectSettings();
    }

    public void Render() 
    {
        RenderJSProperties();
    }
}

Single-Responsibility原则定义如下:

A class should have only one reason to change.

所以这就是为原因找到正确的措辞。然而,这个原因只有在上下文中才有意义,换句话说,在特定的抽象层次上。通过在抽象层次中移动,代码改变了它对 Single-Responsibility 原则的遵从性。

您的经历可能与以下事实有关:您对所用框架的了解有所提高,因此您的理解正在转向更具体的抽象(接近框架内部)。在这个级别上,您的代码做得太多了(因为您预见到有很多更改的理由)。做一个脑力练习并尝试转向应用程序的抽象,它的作用和原因以及 re-evaluate 与 SRP 的一致性。

这里的字典几乎是原始类型;它用于存储键值对,仅此而已(?)。我看不到您需要将它换成不同的实现,而这正是 IOC 有用的地方。 作者作为 IOC 更有意义(你做了):我可以看到需要稍后输出为 xml,或作为字符串等

"too many responsibilites" 一侧。从你描述这个 class 做什么的句子中,1)检测特殊属性,2)呈现一些 js。这里可能有分裂的可能。如果此 class 只是检测到属性并在 C# 对象中返回那些检测到的属性会怎么样。然后其他一些 class,JavascriptRenderer 可能会接受这些属性并转换为 javascript。

var pi = JavascriptPropertyInitializer(containerObject, javscriptObjectName);
var r = JavascriptRenderer(writer);
var output = r.Render(pi.DetectAttributes());

我也经常发现自己对不遵守编码原则感到偏执。这时,我只是尽力而为。当原则明显或有用时,我会应用它,但当我不确定时,我尽量不要太担心它并继续前进。当我的代码变得难以处理时,我知道我可以回去重构并安慰自己。