اصل (LSP)Liskov substitution principle

اصل (LSP)Liskov substitution principleاصل جایگزینی Liskov بیان می کند که سلسله مراتبی از کلاس ها باید به گونه ای طراحی شود که اگر بخواهیم کلاس والد را با یکی از فرزندان آن جایگزین کنیم، کد همچنان همانطور که انتظار می رود کار کند . این بدان معناست که تغییرات در کد فرزند نباید اقدامات منطقی و مورد نظر یک کلاس را به گونه ای تغییر دهد که عملکرد مورد انتظار دیگر پشتیبانی نشود. روش دیگری برای نگاه کردن به این اصل این است که کلاس‌ها در یک سلسله مراتب نباید خیلی از هدف اصلی کلاس والد دور شوند.به عبارت دیگر، هر زیر کلاس باید تمام رفتارهای کلاس پایه را به همراه هر رفتار جدید منحصر به فرد خود حفظ کند. کلاس فرزند باید بتواند همه درخواست‌های مشابه را پردازش کند و تمام وظایف مشابه کلاس والد خود را تکمیل کند.نکته : این اصل فقط یک بسط از Open Closed Principle است و به این معنی است که ما باید اطمینان حاصل کنیم که کلاس های مشتق شده جدید، کلاس های پایه را بدون تغییر رفتارشان گسترش می دهند.همان مثال مربع، مستطیل و چهارضلعی ها(انتخاب سطح صحیحی از انتزاع یا Abstraction)توضیح در مورد مثال مربع و مستطیل : گاهی اوقات چیزی که در زبان طبیعی درست به نظر می رسد در کد کاملاً کار نمی کند.در ریاضیات مربع یک مستطیل است. "است" باعث می شود بخواهید این را با وراثت مدل کنید. با این حال، اگر در کد، Square را از Rectangle مشتق کرده اید، مربع باید در هر جایی که انتظار دارید یک Rectangle قابل استفاده باشد. این باعث ایجاد برخی رفتارهای عجیب و غریب می شود. کمی در مورد آنچه ممکن است اتفاق بیافتد فکر کنید ! چرا این مثال را دوست دارم؟زیرا یک چیز بسیار مهم در مورد OOP را نشان می دهد. OOP تنها در مورد نگاشت ساده دنیای واقعی به اشیا نیست.OOP در مورد ایجاد انتزاعات است، نه مفاهیم!class Program { static void Main(string[] args) { Rectangle rectangle = new Rectangle { Width = 7, Height = 6 }; Console.WriteLine(rectangle.GetArea()); //output is 42 rectangle = new Square { Width = 7, Height = 6 }; Console.WriteLine(rectangle.GetArea()); //output is 49 } } public class Rectangle { public int Width { get; set; } public int Height { get; set; } public virtual int GetArea() { return Width * Height; } } public class Square : Rectangle { public override int GetArea() { return Width * Width; } }چگونه می توان این وضعیت را با استفاده از اصل Liskov حل کرد؟ ساده ترین راه این است که یک کلاس انتزاعی Shape تعریف کنیم که دارای ویژگی های Width و Height باشد. و هر دو کلاس Rectangle و Shape از آن ارث می برند. پیاده سازی (Implementation)//does not follow LSP class Program { static void Main(string[] args) { Apple apple = new Orange(); Debug.WriteLine(apple.GetColor()); } } public class Apple { public virtual string GetColor() { return &quotRed&quot } } public class Orange : Apple { public override string GetColor() { return &quotOrange&quot } }مثال فوق از LSP پیروی نمی کند زیرا کلاس Orange نمی تواند بدون تغییر در خروجی برنامه جایگزین کلاس Apple شود. متد GetColor() توسط کلاس Orange باطل می شود(overridden) و بنابراین نشان می دهد که یک سیب نارنجی است!!!بیایید کد فوق را Refactor کنیمبرای تغییر این موضوع، یک کلاس انتزاعی(abstract) برای Fruit اضافه می کنیم که هم Apple و هم Orange آن را پیاده سازی می کنند.class Program { static void Main(string[] args) { Fruit fruit = new Orange(); Debug.WriteLine(fruit.GetColor()); fruit = new Apple(); Debug.WriteLine(fruit.GetColor()); } } public abstract class Fruit { public abstract string GetColor(); } public class Apple : Fruit { public override string GetColor() { return &quotRed&quot } } public class Orange : Fruit { public override string GetColor() { return &quotOrange&quot } }بیشتر بخوانید : اصول طراحی نرم افزار Software Design Principles