- vừa được xem lúc

Bóc tách nguyên lý Solid: Chìa khóa cho Code "sạch" và linh hoạt (P1)

0 0 1

Người đăng: Thái Thịnh

Theo Viblo Asia

Nguyên lý SOLID là tập hợp 5 nguyên lý thiết kế hướng đối tượng (OOP) giúp lập trình viên tạo ra phần mềm dễ bảo trì, linh hoạt và dễ mở rộng. Bài viết này sẽ giải thích chi tiết từng nguyên lý và cách áp dụng chúng để cải thiện thiết kế phần mềm.

Giới thiệu về Nguyên lý SOLID

Nguyên lý SOLID là tập hợp 5 nguyên lý thiết kế trong lập trình hướng đối tượng (OOP) giúp các nhà phát triển tạo ra phần mềm dễ bảo trì, linh hoạt và có khả năng mở rộng. Trọng tâm chính của những nguyên lý này là gì? Các nguyên lý này nhằm cải thiện thiết kế phần mềm và khuyến khích các phương pháp hay nhất. Vậy nên, nguyên lý SOLID thực chất là 5 nguyên lý được kết hợp trong từ "SOLID". Cùng tìm hiểu chi tiết nhé!

1- S => Single Responsibility Principle (SRP) 2- O => Open/Closed Principle (OCP) 3- L => Liskov Substitution Principle (LSP) 4- I => Interface Segregation Principle (ISP) 5- D => Dependency Inversion Principle (DIP)

Đây là 5 nguyên lý, bây giờ là lúc đi sâu vào từng nguyên lý.

1. Nguyên lý đơn nhiệm (Single Responsibility Principle - SRP)

  • Định nghĩa: Một lớp chỉ nên có một lý do để thay đổi, nghĩa là nó chỉ nên có một chức năng.
  • Lợi ích: Giảm độ phức tạp và cải thiện khả năng bảo trì mã bằng cách đảm bảo mỗi lớp xử lý một chức năng duy nhất.

"Nếu bạn không thấy nó hợp lý, hãy xem ví dụ tiếp theo, nếu không thì cứ bỏ qua"

//Violate SRP
public class UserManager { public void AddUser(string Email , int Id) { //Some code.... } public void SendEmailToUser(int Id) { //Some code.... } public void SendReportToUser(string Email) { //Some code.... }
}

Câu hỏi 1: Bạn nghĩ chúng ta nên làm gì để tuân theo nguyên lý Đơn Nhiệm (SR)?

Ví dụ dưới đây sử dụng một lớp UserManager để thực hiện nhiều hơn một chức năng (AddUser, SendEmailToUser, SendReportToUser). Để tuân theo SRP, mỗi lớp chỉ nên thực hiện một chức năng.

//Following the SRP public class UserManager{ public void AddUser(string Email , int Id) { //Some code.. }
} public class EmailService{ public void SendEmail(int Id) { //Some code.. }
} public class ReportService{ public void SendReport(string Email) { //Some code.. }
}

2. Nguyên lý Đóng/Mở (Open/Closed Principle - OCP)

  • Định nghĩa: Các thực thể phần mềm (Lớp, Mô-đun, Hàm) nên có thể mở rộng, nhưng không thể sửa đổi. Tức là mở để mở rộng và đóng để sửa đổi.
  • Lợi ích: Các chức năng mới có thể được thêm vào mà không làm thay đổi mã hiện có, giảm nguy cơ gây ra lỗi.

Hãy xem một ví dụ về vi phạm OCP.

public class PaymentService { public void PaymentProccess(string paymentType) { if(paymentType == "PayPal") { //Some code.... } if(paymentType == "CreditCard") { //Some code.... } if(paymentType == "BitCoin") { //Some code.... } }
} 

Câu hỏi 2: Bạn nghĩ ví dụ cuối cùng vi phạm OCP như thế nào?! Bây giờ hãy tái cấu trúc theo OCP.

// #1: Create a interface
public interface IPaymentService { void process();
} // #2: Implement Payment Classes
public class PayPalPayment : IPaymentService { public void Process() { //Some code.. }
} public class ICreditCardPayment : IPaymentService { public void Process() { //Some code.. }
}

Theo cách này, chúng ta đã làm cho mã của mình tuân theo OCP. Như thế nào?! Trước khi tái cấu trúc theo OCP, chúng ta phải thêm một câu lệnh if để kiểm tra paymentType. Sau khi tái cấu trúc theo OCP, chúng ta có thể dễ dàng chỉ cần thêm một lớp để xử lý paymentType mà không cần thay đổi mã cơ sở!

Public class BitcoinPayment : IPaymentService { public void Process() { //Some code.. } } 

3. Nguyên lý Thay thế Liskov (Liskov Substitution Principle - LSP)

  • Định nghĩa: Các đối tượng của lớp cha phải có thể thay thế bằng các đối tượng của lớp con mà không ảnh hưởng đến tính đúng đắn của chương trình. Nói cách khác, giả sử bạn có một lớp cha gọi là [A] và lớp con gọi là [B], bạn sẽ có thể sử dụng [B] ở bất cứ đâu mà lớp [A] được sử dụng.
  • Lợi ích: Khả năng bảo trì. Mã cơ sở sẽ không thay đổi hoặc bị ảnh hưởng khi bạn thêm mã hoặc chức năng bên ngoài.
//Superclass
public class Bird { public virtual class Fly { Console.WriteLine("This bird is flying"); } } //Subclass #1
public class sparrow : Bird { public override void Fly() { Console.WriteLine("The sparrow is flying"); } } //Subclass #2
public class Penguin : Bird { //Surely penguins can't fly.. So we are passing incorrect info.. public override void Fly { throw new NotImplementedException("Penguins can't fly!"); } }

Điều này vi phạm LSP. Bởi vì nếu chúng ta sử dụng lớp penguin ở bất cứ đâu mà đối tượng Bird được mong đợi, chương trình sẽ hoạt động không như mong muốn. Việc gọi Fly trên lớp penguin sẽ ném ra một ngoại lệ... chim cánh cụt không thể bay!

Câu hỏi 3: Bạn có thể thử tìm ra cách tôi sẽ đạt được LSP không??

public abstract class Bird { public abstract void Display();
} //Create interface for flying behavior..
public interface IFlyable { void Fly();
} //Now we cant implement the subclass correctly...
public class sparrow : Bird, IFlyable { public override void Display () { Console.WriteLine("This is a sparrow!!"); } public void Fly() { Console.WriteLine("This sparrow is flying"); }
} public class penguin : Bird { public override void Display () { Console.WriteLine("This is a pneguin!"); } }

4. Nguyên lý Đảo ngược Sự phụ thuộc (Dependency Inversion Principle - DIP)

  • Định nghĩa: Các mô-đun cấp cao không nên phụ thuộc vào các mô-đun cấp thấp. Cả hai nên phụ thuộc vào trừu tượng (Interface/Abstract Classes).
  • Lợi ích: Giảm sự ràng buộc chặt chẽ giữa các thành phần, làm cho hệ thống linh hoạt hơn và dễ dàng tái cấu trúc hoặc thiết lập lại hơn.

Tạm thời kết thúc phần 1 tại đây, hẹn gặp lại các bạn ở phần 2 của bài viết nhé.

Bình luận

Bài viết tương tự

- vừa được xem lúc

SOLID trong lập trình hướng đối tượng (P2)

Chào mọi người, trong bài viết trước mình đã giới thiệu 2/5 tính chất của SOLID, ở bài viết này mình sẽ giới thiệu 3 tính chất còn lại. Mọi người hãy chuẩn bị 1 tách cafe, 1 tâm hồn đẹp để đọc và thấm nhuần bài viết này nhé .

0 0 38

- vừa được xem lúc

SOLID trong lập trình hướng đối tượng (P1)

SOLID là tập hợp những nguyên tắc mà mỗi lập trình viên cần tuân theo khi thiết kế cấu trúc 1 class trong lập trình hướng đối tượng. SOLID bao gồm 5 tính chất, 5 tính chất này giúp chúng ta phần nào hiểu được sự cần thiết nhất định của design patterns và software architecture trong lập trình nói chu

0 0 35

- vừa được xem lúc

Nguyên lý S.O.L.I.D trong JavaScript (P3)

Ở bài này chúng ta cùng tìm hiểu về nguyên lý thứ 4 của SOLID, đó là Interface Segregation principle thông qua 2 mục:. . Nguyên lý Interface Segregation là gì . .

0 0 58

- vừa được xem lúc

Áp Dụng Nguyên Tắc SOLID Trong Lập Trình

Giới Thiệu. 1. SOLID là gì. SOLID là viết tắt của 5 chữ cái đầu trong 5 nguyên tắc:.

0 0 37

- vừa được xem lúc

Nguyên lý S.O.L.I.D. trong JavaScript (P4)

Hi mọi người, trong các bài viết trước chúng ta đã tìm hiểu về 4 nguyên lý đầu tiên của SOLID, trong bài viết này, chúng ta cùng tìm hiểu về chữ cái cuối cùng nhé. 1.

0 0 33

- vừa được xem lúc

Áp dụng SOLID trong Android

1. SOLID là gì. Thử tưởng tượng bạn đang ở trong một thư viện sách. Bạn muốn tìm một cuốn sách nào đó.

0 0 85