2023-05-07 13:04:56
Provides guidance on how to use
Let Φ(x) be a property provable about objects x of type T. Then Φ(y) should be true for objects y of type S where S is a subtype of T.
Barbra Liskov (1087) - An elitist who overcomplicates simple concepts
IS-A
A square
HAS-A
A square
A rectangle
A Square has an invariant rule:
A Rectangle has an invariant rule:
IS-SUBSTITUTE-FOR
A rectangle IS-SUBSTITUTE-FOR a square.
NOT IS-SUBSTITUTE-FOR
A square is NOT IS-SUBSTITUTE-FOR a rectangle.
Detecting LSP Violations in Your Code
-
Type Checking
Type checking with
is oras in polymorphic code.foreach (var employee in employees) {
if (employee == null) <-- LSP Violation, because null checking. { Console.WriteLine("Employee not found."); break; }Employee collection should not contain nulls. if (employee is Manager) <-- LSP Violation, because type checking { Helpers.PrintManager(employee as Manager); break; } Helpers.PrintEmployee(employee); }We have a type check therefore LSP is broken. Additional
if
statements will have to be added for every additional employee type.To make each employee type substitutable we can do one of the following:
foreach (var employee in employees) Helpers.Print(employee);
Override the Print method to accept an employee or manager type. OR
foreach (var employee in employees) employee.Print();
Move print functionality into the employee. This may violate SRP . Not Implemented Exceptions
Methods in classes return
NotImplementedException .public class SmtpNotificationService : INotificationService { public void SendEmail(string to, string from, string body) {
// Send email code } public void SendText(string SMSNumber, string message) {throw now NotImplementedException(); } }This is not substitutable for theINotificationService
.Learn More
Pluralsight course: Design Patterns Library
Polymorphism
IS-A
IS-A
LSP
IS-Substitutable
IS-Substitutable
Fixing LSP Violations
- Follow the
"Tell, Don't Ask" principle. Don't ask instances for theirType
and then conditionally perform different actions. Instead, encapsulate that logic into the type instead then tell it to perform that action. - Minimise null checks with:
- Use C# features
- Guard clauses
- Null Object design pattern
- Follow ISP and be sure to fully implement interfaces.
Key Takeaways
- Subtypes must be substitutable for their base types
- Ensure base type invariants are enfored
- Look for:
- Type checking
- Null checking
- NotImplementedException