Sunday, November 7, 2010

[Tutorial] S.O.L.I.D. quality code in C#
Part2: Single Responsibility Principle (SRP)

This is the first principle that I want to show you that will help you to create code that is much less coupled. Code based on this principle becomes much easier to maintain, to evolve and to understand.

Most developers have the tendency to put too much functionality into a single class. Sometimes this is due to bad design, sometimes this is due to the extension of existing code.

Behaviors that should be independent are put together. Those behaviors get tightly coupled and dependant on each other. Changes to a single behavior might impact the other parts of the class (other behaviors).

This may lead to regressions and problems when code needs to be maintained or extended.

The Single Responsibility Principles explains that a class should only have one and a single responsibility. It should serve for only one purpose. Behaviors that belong together must be encapsulated in a single class. But behaviors that are independent from each other must be located in different classes.

When developing new code (or when extending existing code) there needs to be a first phase of conception and design. Within this phase an unordered list of all behaviors and methods is generated, necessary to fulfill the needs of the application (or describing the extensions).

Based on this list the developer creates the class model. Each class generated has a single responsibility. He takes each of the entries in the list and either affects them to existing classes or creates new classes (if the responsibility is not yet covered).

When looking at the following (very simple) example it becomes clear what needs to be done.


The class Modem has more than one responsibility:

  • Connection Handling (Dial and HangUp)
  • Data Transfer (Receive and Send)

To avoid this tight coupling 3 different class must be created that may then be used together in aggregation or composition.


Thus each class class has now only one responsibility:

  • Connection : Connection Handling (Dial and HangUp)
  • Data Channel : Data Transfer (Receive and Send)
  • Modem : Regroups the necessary functionality

Modifications to Connection Handling and Data Transfer can now be done independently in each corresponding class without any impact.



Efim Zabarsky said...

Thank you very much for a very good post!

Pravin said...

Thanks for the tutorial. I have a comment regarding the solution you suggested at the end of article.

Doesn't the structure of having properties complicate the Modem class a little? The user of class will have to think about which property to use for a particular behavior. Do you think we can also implement it this way:
- Keep the methods Dial, Hangup etc. as it is in Modem class
- But these methods don't have any implementation in the Modem class
- These methods in turn can call the DataChannel and Connection methods
- The DataChannel, Connection are hidden to the user

Would like to know what you think about it.

Jason De Oliveira said...

Yes you could extend the example and combine the SRP principle with the facade pattern thus masking the internal processing from the developer as you explained.