SOLID in the acronym, named by Michael Feathers, that
represents five design principles present in Object
Oriented Programming. The theory of these principles was
explained by Robert C. Martin, in the
lecture Design Principles and Design Patterns. In this paper, Uncle Bob describes how the software
can present some symptoms of rotting design, like:
- Rigidity: tendency of the software to be difficult to change. The most common reason is the higher interchangeability between the modules that compose the program;
- Fragility: the tendency of the software to break in many places, every time it is changed. Sometimes this can occur in areas not related directly with the area that was changed;
- Immobility: when it’s nos possible to reuse the software or parts of it in other projects, because of the dependencies. The solution is to rewrite everything;
- Viscosity: when the development team needs to implement some “hacks” to preserve the current behavior (front or back).
The idea of SOLID principles is to solve the problems
above, with some techniques that can provide the software
design more understandable, flexible and
maintainable.
SRP - Single Responsibility Principle
“A class should only, and only one, reason to
change”
This means that a class should have the
responsibility over a single part of the functionality
provided by the software. If you have a class with
many dependencies (reasons to change), one change can
have directly influence in the entire code, and one
change can break everything. Look at this
example:
This class has lots of behaviors: validate email,
connect with database and send email. The objective of
AddClient() method should be add the client, just
this, without worry about database connection, the
mail settings or validation strategies:
We can divide the class, to provide unique
behaviors. This class is now responsible. It has the
properties, and the condition to validate it’s own
consistency. The rules to validate specific
properties (like email), are implemented in specific
services (unique responsibility again):
EmailService class, responsible to manage
emails:
This is the repository class, with the
responsibility focused on the connection with the
database:
The ClientService class, responsible to add the
client:
OCP – Open/Closed Principle
“Software entities (classes, modules, functions,
etc.)
should be open for extension, but closed for
modification.”
Through OCP, it’s possible to create extensible
modules, without the necessity of change the
existing code, when you add some new feature.
Abstraction is the key of OCP.
Here is the example of a Product class, that
contains properties like Size and Color:
If your boss comes with the idea to add some
filter, you can solve this in an easily way, adding
a simple class:
Few days after, you must add another filter (by
Color) and, after some time, another filter
(this time by Color and Size). You can perceive that
this class, ProductFilter, is not open for
extension, just for modification, breaking the OCP
Principle. How can we solve the problem?
Let’s use the Specification Pattern, to create a
Filter that create an abstraction to our
validation:
And now we can have our particular implementation
of the filter, and add many mores if you
want:
And now we can use in a more focused way, using the
correct specification:
LSP – Liskov Substitution Principle
“Subclasses should be substitutable for their base
classes”
If it looks like a duck, quacks like a duck, but
need batteries,
you probably have the wrong abstraction
The Liskov Principle, introduced by Barbara Liskov
in 1987 explains how objects in a program should be
replaceable with instances of their subtypes without
altering the correctness of that program.
In this example, we have a problem between the base
class and the subclasses:
To solve the problem, we can create a new class above
both:
ISP – Interface Segregation Principle
“No client should be forced to depend on methods it
does not use”
This principle defines that it is better to use
lots of specific interfaces rather than a single
one. This strategy provides a more decoupled
solution, turning into an easier to refactor and
change solution.
Suppose that you have an interface to implement
different types of interactions in a
document:
The implementation sounds good isn’t it?
But now, if we want to implement an Old Fashioned
Printer that will have only the Print feature, we
should expose all the methods that are defined in
the interface:
The solution for this, is turn into a more atomic
solution. First thing is to divide the interface
into multiple interfaces with single purpose:
And now we can define a class specifically for the
purpose of scanning and printing, for example:
Another strategy is to create multiple specific
interfaces, and use the Decorator Pattern to solve
the dependencies:
DIP – Dependency Inversion Principle
“High-level modules should not depend on low-level
modules.
Both should depend on abstractions.
Abstractions should not depend on
details.
Details should depend on abstractions.”
The dependency inversion principle is a way for
decoupling our application. The idea is to depend on
an abstraction (e.g. interfaces), not directly from
one implementation.
Remember the class Client of the SRP example?
Here we have a tightly couple EmailServices that
Client depends on. Any change in this concrete
class can break the class Client entirely:
Same problem here in the ClientService. This
class has a directly dependence with
ClientRepository and EmailService classes:
The solution is to expose the classes that I’ll
inject as interfaces. In this case
IEmailServices:
And now, I can inject in the Client class. It’s
low coupled now:
Same thing for ClientService:
Just one observation: for this code to work, we
should use a dependency injection container. You
should tell the container what the concrete class
you should instantiate, according with the
interface you are injecting. They are lot’s of
different container you can use to do this. The
.NET Core has his own DI container, and I’ve added
a list of container in the references.
References used for the examples:
I hope this material can be
useful for you in your studies. You can clone
the Github repository with the code I used in the examples.
Thank you.
No comments:
Post a Comment