Skip to main content

SOLID - Design patterns

SOLID este un acronim de la:
SRP - The Single Responsibility Principle: o clasa ar trebui sa aibe o singura responsabilitate;
OCP - The Open Closed Principle: o clasa trebuie sa fie deschisa la extindere fara a necesita modificarea ei;
LSP - The Liskov Substitution Principle: clasele derivate pot sa fi inlocuite de clasele de baza;
ISP - The Interface Segregation Principle: interfete cu granulatie fina, specifice unei anumite responsabilitati, specifice unui anumit client;
DIP - The Dependency Inversion Principle: dependintele trebuie sa fie definite prin interfete si clase abstracte si nu prin clase concrete;

The Single Responsibility Principle( SRP)
"There should never be more than one reason for a class to change." — Robert Martin

O clasa trebuie sa faca doar in singur lucru si nimic mai mult. Fiecare clasa in parte trebuie sa aiba o singura responsabilitate. O clasa care are o singura responsabilitate este mai usor de modificat, mult mai usor de inteles si mai usor de testat. Totodata daca o clasa are mai multe responsabilitati avem mai mari sanse ca acelasi cod sa apara si in alte clase.
O clasa care are mai multe functionalitati este prea mare, face prea multe si este mult prea complicata. Cel mai usor lucru pentru a rezolva aceasta problema este sa facem split la clasa.

Open Closed Principle( OCP)
"Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification." — Robert Martin

O clasa trebuie sa fie deschisa spre extindere si inchisa spre modificare. Comportamentul unei clase ar trebui sa fie modificat prin mostenire si prin compozitie. Principala idee este ca functionalitatile logice sa fie cat mai bine definite, iar daca este cazul acestea sa fie mutate in alte clase si referite prin intermediul interfetelor.
De exemplu daca avem o clasa ce face validarea unui obiect, aceasta nu trebuie sa contina si regulile de validare. Acestea pot sa fie referite prin intermediul unei interfete si transmise prin constructor. In felul acesta daca regulile se modifica, nu o sa fie necesar sa modificam clasa care face validarea. Astfel regulile de validare o sa poata fi schimbate mult mai usor.

Liskov Substitution Principle( LSP)
"Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it." — Robert Martin

Ideea de baza este ca putem inlocui instanta unei clase cu subclasa fiu si totul sa functioneze normal. Nu este tocmai usor de facut acest lucru, deoarececlasa poate sa aibe un set de actiuni specifice care sa nu se mai regăsească in clasa fiu.
Un bun exemplu este exemplu clasic cu dreptunghiul si patratul, unde un patratul poate sa mosteneasca din dreptunghi dar laturiile deja difera ca denumire si logica.
Dar asta nu inseamna ca nu trebuie sa incercam sa respectam LSP. Trebuie sa incercam sa facem clasele de baza cat mai generice. Aceasta regula nu se aplica mereu, dar exista cazuri cand este foarte utila. De foarte multe ori nu putem modela obiectele exact la fel cum sunt in lumea reala prin mostenire, dar ne putem folosi de compozitie pentru acest lucru.

Interface Segregation Principle( ISP)
"Clients should not be forced to depend upon interfaces that they do not use." —Robert Martin
Fiecare interfata trebuie sa fie cat mai simpla si sa defineasca un singur lucru( sa fie specifice). In cazul in care avem o interfata foarte mare, cel mai bine este ca aceasta sa fie sparta in functie de ce responsabilitati are. In cazul in care avem mai multe functionalitati intr-o clasa, atunci in clasa respectiva va fi nevoie sa implementam toate interfetele de care avem nevoie. De multe ori daca avem o interfata foarte mare, clientul nu o sa aibe nevoie sa implementeze toate functiile, ci doar o parte din ele, a.i. se ajunge ca o mare parte din metode sa nu fie implementate.

Dependency Inversion Principle( DIP)
"A. High level modules should not depend upon low level modules. Both should depend upon abstractions.
B. Abstractions should not depend upon details. Details should depend upon abstractions." — Robert Martin
Daca o clasa are dependinte fata de alte clase, acestea ar trebui sa fie prin interfete si clase abstracte si nu prin clase concrete. Prin acest mod clasele se pot modifica mult mai usor, o sa fie mult mai decuplata si mult mai usor de testat.
Daca respectam acest principiu, putem folosi Dependency Injection fara nici o problema. Totodata putem mult mai usor sa separam nivelele unei aplicatii.

Comments

  1. Ma tem ca Liskov substitution principle e un pic invers: se poate inlocui o instanta a unei clase de _baza_ cu o instanta a unei clase derivate (subclasa) a.i. toate proprietatile (preconditiile, postconditile, invariantii) aferente raman valabile (la nivel semantic, nu doar sintactic)

    ReplyDelete
  2. Catdespre Dependency Inversion, se poate formula si altfel, mai intuitiv: daca o clasa A are nevoie de serviciile unei alte clase B, prima clasa ar trebui sa defineasca o interfata I si doar sa se asigure ca obtine (sau i se furnizeaza) o instanta ce expune interfata I (care in practica va fi implementata de clasa B sau de un adapter ce apeleaza B).

    ReplyDelete

Post a Comment

Popular posts from this blog

How to check in AngularJS if a service was register or not

There are cases when you need to check in a service or a controller was register in AngularJS.
For example a valid use case is when you have the same implementation running on multiple application. In this case, you may want to intercept the HTTP provider and add a custom step there. This step don’t needs to run on all the application, only in the one where the service exist and register.
A solution for this case would be to have a flag in the configuration that specify this. In the core you would have an IF that would check the value of this flag.
Another solution is to check if a specific service was register in AngularJS or not. If the service was register that you would execute your own logic.
To check if a service was register or not in AngularJS container you need to call the ‘has’ method of ‘inhector’. It will return TRUE if the service was register.
if ($injector.has('httpInterceptorService')) { $httpProvider.interceptors.push('httpInterceptorService&#…

ADO.NET provider with invariant name 'System.Data.SqlClient' could not be loaded

Today blog post will be started with the following error when running DB tests on the CI machine:
threw exception: System.InvalidOperationException: The Entity Framework provider type 'System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer' registered in the application config file for the ADO.NET provider with invariant name 'System.Data.SqlClient' could not be loaded. Make sure that the assembly-qualified name is used and that the assembly is available to the running application. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information. at System.Data.Entity.Infrastructure.DependencyResolution.ProviderServicesFactory.GetInstance(String providerTypeName, String providerInvariantName) This error happened only on the Continuous Integration machine. On the devs machines, everything has fine. The classic problem – on my machine it’s working. The CI has the following configuration:

TeamCity.NET 4.51EF 6.0.2VS2013
It seems that there …

Run native .NET application in Docker (.NET Framework 4.6.2)

Scope
The main scope of this post is to see how we can run a legacy application written in .NET Framework in Docker.

Context
First of all, let’s define what is a legacy application in our context. By a legacy application we understand an application that runs .NET Framework 3.5 or higher in a production environment where we don’t have any more the people or documentation that would help us to understand what is happening behind the scene.
In this scenarios, you might want to migrate the current solution from a standard environment to Docker. There are many advantages for such a migration, like:

Continuous DeploymentTestingIsolationSecurity at container levelVersioning ControlEnvironment Standardization
Until now, we didn’t had the possibility to run a .NET application in Docker. With .NET Core, there was support for .NET Core in Docker, but migration from a full .NET framework to .NET Core can be costly and even impossible. Not only because of lack of features, but also because once you…