Liskov Substitution Principle là gì?

Vào năm 1987, Barbara Liskov, nhà nữ khoa học máy tính người mỹ đã phát biểu Liskov Substitution Principle (LSP) như sau:

“If S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e. an object of type T may be substituted with any object of a subtype S) without altering any of the desirable properties of the program”

Nếu S là kiểu mở rộng của T, thì S có thể được sử dụng thay thế cho T mà không thay đổi cấu trúc phần mềm. Hay nói cách khác phần mềm nên được thiết kế bởi các thành phần dễ dàng hoán đổi cho nhau.

LSP nhấn mạnh về tính kế thừa class hay sự mở rộng interface, nó khiến bạn phải suy nghĩ thấu đáo về việc sử dụng tính chất này hợp lý trong việc thiết kế phần mềm.

Ví dụ:

Thiết kế chương trình tính toán tiền lương của người lao động, được biết trong công ty có 2 kiểu lao động đó là Staff và Manager.

Hệ thống tính lương

Source code:

https://github.com/mt26691/learning-solid/blob/master/SOLID/SOLID.LiskovSubstitutionPrinciple.RightDesign/Program.cs

Lớp Staff và Manager cùng mở rộng interface IEmployee, do vậy chúng có thể được sử dụng thay thế cho nhau. Module Billing khi gọi hàm CalculateSalary không cần quan tâm đến object đang chạy là Staff hay Manager, đơn giản vì chúng có thể được thay thế hoàn toàn cho nhau. Đây là thiết kế đúng, phù hợp với LSP.

Vấn đề hình vuông, hình chữ nhật.

Vấn đề hình vuông/chữ nhật, hay hình tròn/eclip là vấn đề nổi tiếng khi đề cập về LSP.

Hình vuông là một trường hợp đặc biệt của hình chữ nhật với hai cạnh bằng nhau. Như vậy khi thiết kế phần mềm, class Square có thể thay thế class Rectangle được hay không?

Ví dụ: Thiết kế chương trình tính diện tích hình vuông/hình chữ nhật.

Vấn đề hình vuông, hình chữ nhật

Vấn đề hình vuông, hình chữ nhật

class Square (hình vuông) kế thừa class Rectangle (hình chữ nhật). Để tính diện tích của hình vuông, ta chỉ cần biết giá trị một cạnh, do vậy ta chỉ cần hàm SetSide.
Để tính diện tích hình chữ nhật, bạn cần biết hai cạnh. Vì thế hình vuông trong trường hợp này không phải là một kiểu của hình chữ nhật. Thiết kế này đã vi phạm nguyên tắc LSP.

Rectangle rec = new Square();


rec.SetHigh(5);

rec.SetWidth(10);

rec.CalculateSquare(); //kết quả = 50

Source code:

https://github.com/mt26691/learning-solid/blob/master/SOLID/SOLID.LiskovSubstitutionPrinciple.WrongDesign/Program.cs

Điều gì xảy ra khi chạy đoạn code trên? Giá trị trả về là 50. Nếu object thực chạy là hình chữ nhật (Rectangle), có chiều cao 5, chiều rộng 10 thì đây là kết quả đúng. Rất tiếc trong trường hợp này, object thực chạy là hình vuông (Square), làm gì có hình vuông nào có chiều cao bằng chiều rộng. Do đó class Square (lớp con) không thể thay thế class Rectangle (lớp cha) trong trường hợp này. Thiết kế này đã vi phạm nguyên tắc LSP.

Nếu tôi đặt giá trị chiều dài chiều rộng bằng nhau thì kết quả vẫn chạy đúng!

Sai, để đảm bảo kết quả chạy đúng bạn phải đặt chiều dài và chiều rộng bằng nhau, nếu vì một lý do nào đó mà chiều dài hay chiều rộng khác nhau, kết quả trả về sẽ sai. Như vậy chương trình này hoạt động không ổn định.

Lợi ích của LSP:

Khi thiết kế phần mềm, LSP sẽ giúp cho bạn bạn thực hiện việc kế thừa, mở rộng một cách đúng đắn. Lớp con có thể thay thế hoàn toàn lớp cha được không? Nếu không thì việc kế thừa của bạn đang có vấn đề, cần phải thay đổi thiết kế.

Các module, class khi được thiết kế đúng LSP sẽ phụ thuộc lỏng lẻo vào nhau hơn (Loosely coupled), do đó ta có thể tái sử dụng code dễ dàng hơn. Ở các bài sau, tôi sẽ nói rõ hơn về sự phụ thuộc lỏng lẻo này.

Các môn học khác

Khoa học về dinh dưỡng, giáo trình giảm cân cho mọi người.

Chương trình thường được xây dựng quanh dữ liệu và logic để xử lý chúng. Nói cách khác: Program = Cấu trúc dữ liệu + giải thuật. Do vậy đây là môn học bắt buộc dành cho các lập trình viên.

Khóa học này cung cấp cho ta kiến thức nền tảng về công nghệ Blockchain, Bitcoin. Vì sao nó được gọi là công nghệ của tương lai, vì sao giá Bitcoin lại cao đến vậy. Làm sao để mua Bitcoin, ETH.