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

Windows Docker Containers can make WIN32 API calls, use COM and ASP.NET WebForms

After the last post , I received two interesting questions related to Docker and Windows. People were interested if we do Win32 API calls from a Docker container and if there is support for COM. WIN32 Support To test calls to WIN32 API, let’s try to populate SYSTEM_INFO class. [StructLayout(LayoutKind.Sequential)] public struct SYSTEM_INFO { public uint dwOemId; public uint dwPageSize; public uint lpMinimumApplicationAddress; public uint lpMaximumApplicationAddress; public uint dwActiveProcessorMask; public uint dwNumberOfProcessors; public uint dwProcessorType; public uint dwAllocationGranularity; public uint dwProcessorLevel; public uint dwProcessorRevision; } ... [DllImport("kernel32")] static extern void GetSystemInfo(ref SYSTEM_INFO pSI); ... SYSTEM_INFO pSI = new SYSTEM_INFO(...

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.51 EF 6.0.2 VS2013 It see...

Navigating Cloud Strategy after Azure Central US Region Outage

 Looking back, July 19, 2024, was challenging for customers using Microsoft Azure or Windows machines. Two major outages affected customers using CrowdStrike Falcon or Microsoft Azure computation resources in the Central US. These two outages affected many people and put many businesses on pause for a few hours or even days. The overlap of these two issues was a nightmare for travellers. In addition to blue screens in the airport terminals, they could not get additional information from the airport website, airline personnel, or the support line because they were affected by the outage in the Central US region or the CrowdStrike outage.   But what happened in reality? A faulty CrowdStrike update affected Windows computers globally, from airports and healthcare to small businesses, affecting over 8.5m computers. Even if the Falson Sensor software defect was identified and a fix deployed shortly after, the recovery took longer. In parallel with CrowdStrike, Microsoft provi...