
اصل لسکو (Liskov Substitution Principle - LSP): پایهای ترین اصل SOLID در معماری نرمافزار
اصل لسکو (LSP) که به نام باربارا لسکو، دانشمند کامپیوتر MIT نامگذاری شده است، سومین اصل از اصول SOLID در مهندسی نرمافزار محسوب میشود. این اصل در سال 1987 مطرح شد و امروزه به عنوان اساس طراحی رابطها و وراثت در برنامهنویسی شیءگرا شناخته میشود.
💡 تعریف فنی اصل لسکو:
"اگر S زیرنوع T باشد، آنگاه اشیاء از نوع T باید بتوانند با اشیاء از نوع S جایگزین شوند، بدون اینکه ویژگیهای مطلوب برنامه تغییر کند."
🔍 چرا اصل لسکو مهم است؟
-
جلوگیری از خطاهای غیرمنتظره در زمان اجرا
-
ایجاد قابلیت نگهداری بهتر کد
-
تسهیل توسعه پذیری سیستم
-
کاهش وابستگیهای ناخواسته بین کامپوننتها
⚠️ نقض اصل لسکو: مثال کلاسیک مستطیل-مربع
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Square(Rectangle):
def __init__(self, size):
super().__init__(size, size)
# نقض LSP: تغییر رفتار ستکنندههای والد
@property
def width(self):
return self._width
@width.setter
def width(self, value):
self._width = value
self._height = value # رفتار غیرمنتظره!
مشکل: وقتی Square جایگزین Rectangle شود، تغییر عرض باعث تغییر ارتفاع میشود (رفتاری که از Rectangle انتظار نمیرود).
✅ پیادهسازی صحیح با رعایت LSP
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Square(Shape):
def __init__(self, size):
self.size = size
def area(self):
return self.size ** 2
🛠️ نشانههای نقض LSP
-
Override کردن متدها با رفتار کاملاً متفاوت
-
پرتاب Exceptionهای جدید در زیرکلاس
-
برگشت دادن مقادیر با نوع متفاوت از والد
-
تغییر حالت داخلی شیء به روشی غیرمنتظره
💡 بهترین روشها برای رعایت LSP
-
از اینترفیسها به جای وراثت بتنی استفاده کنید
-
قراردادهای رفتاری را به دقت مستند کنید
-
از Design by Contract پیروی کنید:
-
Preconditions نباید در زیرکلاس تقویت شوند
-
Postconditions نباید در زیرکلاس تضعیف شوند
-
Invariants باید حفظ شوند
-
🌐 کاربردهای واقعی LSP
-
پلاگینهای سیستم: هر پلاگین باید بدون شکستن سیستم اصلی جایگزین شود
-
ماژولهای پرداخت: تمام درگاههای پرداخت باید از یک قرارداد واحد پیروی کنند
-
ذخیرهسازی داده: جایگزینی دیتابیس واقعی با Mock در تستها
java
// مثال در جاوا - سیستم پرداخت
interface PaymentProcessor {
void processPayment(double amount);
}
class PayPalProcessor implements PaymentProcessor {
public void processPayment(double amount) {
// پیادهسازی خاص PayPal
}
}
class StripeProcessor implements PaymentProcessor {
public void processPayment(double amount) {
// پیادهسازی خاص Stripe
}
}
📊 تأثیر LSP بر کیفیت کد
معیار | بدون LSP | با LSP |
---|---|---|
قابلیت تست | ❌ ضعیف | ✅ عالی |
قابلیت استفاده مجدد | ❌ محدود | ✅ بالا |
وابستگیها | ❌ زیاد | ✅ کم |
خطاهای زمان اجرا | ❌ متعدد | ✅ نادر |
🚀 نتیجهگیری: LSP در دنیای مدرن
اصل لسکو امروزه بیش از هر زمان دیگری اهمیت دارد، به ویژه در:
-
معماریهای میکروسرویس
-
توسعه مبتنی بر کامپوننت
-
سیستمهای Plugin-Based
رعایت این اصل مانع از ایجاد شگفتیهای ناخواسته در کد میشود و به شما کمک میکند سیستمهایی انعطافپذیر و قابل نگهداری بسازید.

نویسنده
سیدهادی موسوی
Tags: #تئوری #برنامه_نویسی #مقاله