C# dasturlash tilida SOLID prinsiplari
Tags: solid
Published: 2022-08-04 09:57:00

C# tilidagi SOLID dizayn prinsip bu asosiy kod yozish prinsipidir ya'ni ushbu prinsipga rioya qilib kod yozilsa dastur clean code hisoblanadi.
 SOLID standartlari 5ta quyidagilar:
_1)_ Yagona javobgarlik printsipi (**Single Responsibility Principle** SRP). 
_2)_ Ochiq yopiqlik printsip (**Open closed Principle** OSP). 
_3)_ Liskov almashtirish printsipi (**Liskov substitution Principle** LSP).
_4)_ Interfeyslarni ajratish printsipi (**Interface Segregation Principle** ISP ).
_5)_ Qaramlik ajratish printsipi (**Dependency Inversion Principle** DIP ).



Demak boshladik 🤷‍♀️

## 1) Single Responsibility Principle
**Yagona javobgarlik printsipi** (Single Responsibility Principle ( _**SRP**_ )
 Ushbu pinsipga ko'ra har qanday dasturiy ta'minotni yaratayotganda dasturiy ta'minotni biror modulini o'zgartishga bitta sabab bo'lish kerak bu degani har bir class faqatgina bitta ishni bajarishi kerak. Ya'ni dasturni yozayotganda classlarga qanaqa o'rgatirishlar kiritishimizni yaxshilab o'ylab yozishimiz kerakligini taqozo etadi.
*Misol-1

```
public class User
{
  public ulong UserId {get;set}
  public string FirsName{get;set}
  public string UserName{get;set}
}
```

ushbu user classi faqatgina userni ma'lumotlarni saqlash uchun va unga hechqanday qo'shicha vazifa yuklanmangan!!!✔.


*Misol-2

```

public class User
{
  public ulong UserId {get;set}
  public string FirsName{get;set}
  public string UserName{get;set}
  public void PrintUserData()
  {
    ...
  }
}
```

ushbu user classi faqatgaina userni ma'lumotlari saqlash kerak edi lekin unga PrintUserData() metodini qo'shib qoyganimiz uchun Single Responsibility Prinsiple ga to'gri kelmaydi 

## 2) Open closed Principle 
 **Ochiq yopiqlik printsipi** (Open closed Principle ( _**OSP**_ ))
 Ushbu prinsipga ko'ra  modul yoki class kengaytrish uchun ochiq hamda o'zgartirish uchun esa yopiq bo'lish kerak.
Keling buni bir misol yoradmida ko'rib chiqamiz.



```
public class User
{
  public ulong UserId {get;set}
  public string FirsName{get;set}
  public string UserName{get;set}
  public byte UserType{get;set}
  public double GetDiscount()
  {
    if(UserType==1)
         return 10.0;
    else
         return 50.0;
  }

}
```

quyidagi kodga biz o'zgartirish kiritdik ya'ni UserType ni va GetDiscount metodini yangi qo'shdik bunda GetDiscount metodi UserType ga qarab discountni hisoblab beradi.
Muammo shundaki Agar UserType da o'zgarish bo'lsa qo'shilsa yangi UserType qo'shilsa GetDiscount metodiga yana if blok qo'shilishi kerak bunda User classini ko'pgina joylarda ishlatilgan bo'lsa ko'pgina o'zgarish qilish kerak boladi.Ushbu User classi o'zgartirish uchun uchun yopiq kengaytirish uchun ochiq bo'lmadi. Open close prinspilariga to'gri kelmaydi.Endi o'zgartirishni o'rniga ushbu classni kengaytisak ushbu muammo yuzaga kelishdan qutilamiz. Bu muammoni quyidagicha hal qilish mumkin
Misol-2

```
public class User
{
  public ulong UserId {get;set}
  public string FirsName{get;set}
  public string UserName{get;set}
  public byte UserType{get;set}
  public virtual double GetDiscount(double TotalPrice)
   {
    return TotalPrice;
   }
}
public class PremiumUser:User
{
  public override double GetDiscount(double TotalPrice)
  {
    return base.GetDiscount(TotalPrice)-10;
  }

}
public class SilverUser:User
{
  public override double GetDiscount(double TotalPrice)
  {
    return base.GetDiscount(TotalPrice)-30;
  }
}

public class GoldUser:User
{
  public override double GetDiscount(double TotalPrice)
  {
    return base.GetDiscount(TotalPrice)-50;
  }
}
```

!!!✔
Demak biz User classini kengaytirdik va har xil Userlar uchun har xil User classini kengaytidik va har bir Userdan extend qilingan classlar ozini Disconutini o'zi hisoblaydi.
Agarda yangi turdagi user qo'shiladigan bo'lsa unga yangi User classidan extend qilib yaratamiz va unga o'zini discountini yozib qoyamiz.
Shu bilan dasturni Asosiy User classini o'zgartirmasdan balki uni kengaytirib takomilashtirdigan bo'lamiz.
Bunda User classi o'zgartirishlar uchun yopiq va  kengaytirih uchun yoq hisoblanadi.

## 3) Liskov substitution Principle
 **Liskov almashtirish printsipi** (Liskov substitution Principle ( _**LSP**_ ))
Bu prinspga ko'ra yaratilgan classlar ularning avlod classlari bilan bemalol almashtirishtiriladigan bo'lishi kerak. Ya'ni classdan olinga avlod classi uni ajdod classini o'rnini bosishi kerak. Bu prinsp Ochiq yopiqlik printsipi (Open closed Principle OSP) ning davomi hisoblanadi.
LSP Prinsipiga ko'ra avvalgi prinsipdagi (Open closed Principle OSP) User classini  o'rnini undan olinga PremiumUser, SilverUser va GoldUser classlari bosa olishlari kerak bo'ladi.

## 4) Interface Segregation Principle
 **Interfeyslarni ajratish printsipi** (Interface Segregation Principle ( _**ISP**_ )).
Ushbu prinsipda ko'plab keraksiz metodlardan foydalanmasak ham ularni yozish va bitta katta interfeys qilgandan ko'ra kichik kichik interfeyslarga ajratish. Bunda foydalanganda aynan o'ziga kerakli bo'lgan kichik kichik interfeysladan foydalanib ishlatadi keraksiz narsalarni implement qilishdan saqlandi. 
 *Misol.

```
public class User
{
  public ulong UserId {get;set}
  public string FirsName{get;set}
  public string UserName{get;set}
  public virtual double GetDiscount(double TotalPrice)
    {
      return TotalPrice;
    }
}

public class SilverUser:User
{
  public override double GetDiscount(double TotalPrice)
  {
    return base.GetDiscount(TotalPrice)-30;
  }
}

public class GoldUser:User
{
  public override double GetDiscount(double TotalPrice)
  {
    return base.GetDiscount(TotalPrice)-50;
  }
}

```
Bizda User classi bor va undan GoldUser va SilverUser classlari voris qilib olingan
deylik biz GoldUser DataBase dan o'qib to'liq ma'lumotlarni olishimiz kerak. buning uchun kichik interface yaratamiz

```
interface IDatabaseRead
{
   public void Read(); 
}
```

ushbu interface ni biz faqat GoldUser  classiga imlement qilamiz
shunda Read() metodini yozishga majburlaydi hamda bosqa joylarda ushbu GoldUser ni database dan o'qishimiz uchun type ga IDatabaseRead ni berib uni database dan o'qib olishimiz mumkin.
Shunda GoldUser classi quyodagicha bo'ladi.


```
public class GoldUser:User, IDatabaseRead
{
  public override double GetDiscount(double TotalPrice)
    {
      return base.GetDiscount(TotalPrice)-50;
    }
public override void Read()
  {
    ...
  }
}
```

Shunda biz keraksiz narsalarni qayta yozishdan qutilamiz
va Maind quyidagicha foydalanishimiz mumkin

```
static class Program
{
    static void Main()
    {
       GoldUser user1= new GoldUser();
        user1.Read();
       IDatabaseRead user2= new GoldUser();
        user2.Read(); 
    }
}
```

bunda ayna kerakli interfeysni implement qilshni o'zi yetarli.

## 5) Dependency Inversion Principle
  **Qaramlik ajratish printsipi** (Dependency Inversion Principle ( _**DIP**_ )) 
   1) Yuqori darajadagi modullar quyi darajadagi modullarga qaram bo'lmasligi lozim. Ularni ikkalasi ham abstracsiyaga bog'langan bo'lishi lozim ya'ni Yuqori darajdagi classlar quyi darajdagi classlar bilan abstracsiya orqali bog'langan bo'lishini nazarda tutadi.
   2) Abstracsiya tavsilotlarga bog'liq bo'lmasligi kerak aksincha tavsilotlar abstracsiyaga bog'liq bo'lishi kerak.

Ushbu nasalar☝ bilan biz modullar classlarni bir birga bog'liqligini kamaytirishga erishamiz

```
public class SendMessage
{
    TextMessage textMessage;
    EmailMessge emailMessage;
  public SendMessage()
  {
    emailMessage = new EmailMessge();
    textMessage = new TextMessage();
  }

  public void Send()
  {
    textMessage.SendTextMessage();
    emailMessage.SendEmailMessage();
  }
}

public class TextMessage
{
  public void SendTextMessage(){...}
}

public class EmailMessge
{
  public void SendEmailMessage(){...}
}

```
Ushbu classlar  bir bir yuqori darajadagi class quyi darajadagi classlarga qaram bop qolgan ba bular abstracsiya orqali emas balki kankret implementatsiyaga bog'liq bo'lib qolgan va DIP ga ko'ra bular bir biriga kankret emas balki abstaksiya orqali bog'langan bo'lishi kerak. Ular orasida kuchli bog'liqlik paydo bo'lgan ya'ni (tightly coupled) bog'lanish deyiladi.
Endi DIP  ga ko'ra ularni abstracsiya orqali bog'lashni ko'rib chiaqamiz.

```
public interface IMessageSender
{
   public void Send();
}

public class SendMessages
{
  IMessageSender message;

  public SendMessages(IMessageSender _message)
    {
      message=_message
    }
  public void SendMessage(){...}
}

public class TextMessage:IMessageSender
{
  public string PhoneNumber{get;set}
  public string Content{get;set}
  public void Send(){...}
}

public class EmailMessage:IMessageSender
{
  public string EmailAddress{get;set}
  public string Subject{get;set}
  public string Content{get;set}
  public void Send(){...}
}

```
Ko'rib turganinggizdek ushbu 2ta class `EmailMessage `va TextMessages  hamda `SendMessages` classlari bir biriga abstracsiya orqali bog'langan ya'ni bu yerda hech qanday konkret bog'lanish yo'q.
Yuqoridagi ikkita `EmailMessage `va `TextMessages `classlarini SendMessages classiga bog'liqligini ketkazidik va aksincha ularni ikkalasiniyam abstrac IMessageSender interfeysiga bog'liq qilib qo'ydik.