Using the “Single Responsibility Principle” forces my containers to have public setters

前端 未结 4 1600
别那么骄傲
别那么骄傲 2021-02-08 23:56

I\'m trying hard to design following the SOLID principles. What I\'ve found is that when you use the \"Single Responsibility Principle\" (the S of SOLID) you usually have to spl

相关标签:
4条回答
  • 2021-02-09 00:10

    Most data access strategies (ORM techniques) involve compromises of the kind you're describing. The least intrusive ones use reflection (or introspection, etc.) to populate your entities when they need to (when no public setters exist, for example).

    Having said that, if your entities are only data containers (as in the anemic domain model), the single responsibility principle shouldn't really concern you much, since your objects don't have complex logic that would be spoiled by (or interfere with) data access code.

    0 讨论(0)
  • 2021-02-09 00:12

    You're thinking too granularly. A specific class should read the database- but you don't need a class whose sole job is to create a Person. That's just wasteful. A single database reader should be capable of creating any class that comes through the database- because that's it's job. To read from the database.

    There's no encapsulation problems with opening Person's properties so that DatabaseReader can access them, as Person is redundant if no class is capable of creating it. It's an inherent part of any classes responsibility to be creatable and destructible.

    0 讨论(0)
  • 2021-02-09 00:17

    I definitely agree with you that sometimes you run into this problem. I've experienced it with serialization, which is similar to ORM. In my case I needed to write the state of an object to a (binary) file.

    In some cases it can be appropriate to create an interface through which the internal state can be written and read. So your person class would get two metheds "save" and "load" (or "write" and "read" or whatever you think is appropriate). These methods are passed a "IPropertyWriter" and "IPropertyReader" respectively. (In my case I called them InStream and OutStream).

    Person::save(IPropertyWriter writer) would then do

    writer.writeProperty("name", this.name);
    writer.writeProperty("age", this.age);
    

    You can argue that you are still violating the Single Responsibility Principle, but I'd argue that nobody else should know the internals of Person. (Especially in my case of Serialization, I had to store the internal state which is partly not accessible through getters). The main point is that Person is not coupled to any Database code. Your IPropertyWriter can be everything. Furthermore, the responsibility for "knowing its own properties" is not really a new property but is attached to every object anyways.

    You might also ask the question how likely it is that Person will change. If it's very unlikely, I think friend classes like in C++ are a good way, but if it's likely to change, I'd rather have the serialization methods right at the place where the properties are declared so you don't forget to update the dependent code.

    0 讨论(0)
  • 2021-02-09 00:19

    Maybe I'm missing something, but why won't you write a constructor for Person class which accepts all it's properties? This way the PersonReader will be able to create a person without you opening the person's properties.

    Another option is to mark the setter of the person's properties as internal (And make the assembly internals visible to the assembly of the PersonReader, if it's in a different assembly). This will allow you to access the person properties, but will prevent anyone to change them outside of the assembly.

    0 讨论(0)
提交回复
热议问题