Search code examples
c#design-patternssolid-principlessingle-responsibility-principle

If an object parse it's own input, is it considered breaking SRP?


If an object parse it's own input, is it considered breaking SRP?

For example

class A
{
    int x;
    string y;
    float f;
    A(string x, string y, string f)
    {
        this.x = int.Parse(x);
        if (this.x < 0 || this.x > 10)
        {
            throw new ArgumentOutOfRangeException();
        }
        this.y = y;
        this.f = float.Parse(f);
    }
}

Or to have a private constructor and use a public static method that parse and checks input and return A.

Instead of passing an int, string and float and parsing and checking if they're valid somewhere else.


Solution

  • Is it breaking single responsibility principle? No, the example given you are parsing primitive types, to construct a basic object, I don't feel in the example code you've given that it's a responsibility in it's own right. SRP is easier to explain given a business domain to operate within...

    To elaborate, parsing as used above is working on primitive data types, the built in parsing on primitive types serves to facilitate conversion of one primitive type to another. The purpose of SRP is not to abstract such core functionality, but to ensure that the design of your code has a single responsibility. For example, when saving a record to the database, you could write a function that picks up the raw data, maps it to the different tables and sends an email to confirm the entry, this is breaking SRP. How do we avoid this in such an example? Using things such as the repository pattern to abstract away the database concerns, having a separate class to manage email communications, perhaps using dependency injection to ensure that these components are readily interchangeable in your solution. Would I seriously try and abstract all basic parsing on primitive types?

    Absolutely not.

    Underpinning the whole concept is the "reason to change", if your code design has more than one reason it would have to change, it's breaking SRP. In the example given, if the email changed, or the raw data, or the mapping to different tables, we'd need to change the code, for 3+ different reasons.

    That being said, your constructor or functions should ideally accept the correct type, there may be reasons as to why you cannot do this, but you should avoid parsing if you can supply the values in the right type.

    One last thing to add: I've seen many developers get hung up on issues such as this relating to primitive types, parsing and constructing objects, attempting to ensure no design principles might be broken, such as SRP. They have spent hours meticulously looking at issues and missed much larger domain design problems as a result. Try to ensure you can see the bigger picture and you don't lose sight of your application architecture. I'm not suggesting you never worry about such things, just don't fall into the trap of missing the bigger problems in designing your applications.