DEV Community

Cover image for C# dasturlash tilida SOLID prinsiplari
Shokhrukh Yarashov
Shokhrukh Yarashov

Posted on

C# dasturlash tilida SOLID prinsiplari

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}
}
Enter fullscreen mode Exit fullscreen mode

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()
  {
    ...
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
  }

}
Enter fullscreen mode Exit fullscreen mode

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

!!!βœ”
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;
  }
}

Enter fullscreen mode Exit fullscreen mode

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(); 
}
Enter fullscreen mode Exit fullscreen mode

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()
  {
    ...
  }
}
Enter fullscreen mode Exit fullscreen mode

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(); 
    }
}
Enter fullscreen mode Exit fullscreen mode

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(){...}
}

Enter fullscreen mode Exit fullscreen mode

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(){...}
}

Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)