اصل جایگزینی لیسکوف در سی شارپ با مثال پرنده

Summarize this content to 400 words in Persian Lang
اصل جایگزینی لیسکوف (LSP) یکی از پنج اصل جامد طراحی شی گرا است.
“اشیاء در یک برنامه باید با نمونه هایی از انواع فرعی خود بدون تغییر در صحت آن برنامه قابل تعویض باشند.”
به عبارت ساده تر، اگر یک کلاس پایه (یا رابط) و یک کلاس مشتق شده دارید، باید بتوانید کلاس پایه را با کلاس مشتق شده جایگزین کنید بدون اینکه خطا یا تغییر رفتار مورد انتظار برنامه را ایجاد کنید.
📌کاوش بیشتر در: https://dotnet-fullstack-dev.blogspot.com/🌟 اشتراک گذاری قدردانی می شود! 🚀
کد مشکل
بیایید با مثالی شروع کنیم که LSP را نقض می کند. یک کلاس پایه Bird و یک کلاس مشتق شده از Ostrich را در نظر بگیرید.
public class Bird
{
public virtual void Fly()
{
Console.WriteLine(“Flying”);
}
}
public class Ostrich : Bird
{
public override void Fly()
{
throw new NotSupportedException(“Ostriches can’t fly”);
}
}
public class Program
{
public static void Main()
{
Bird bird = new Ostrich();
bird.Fly(); // Throws NotSupportedException
}
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
در این مثال،
کلاس Bird یک متد Fly دارد که “Flying” را چاپ می کند.
کلاس Ostrich از Bird به ارث می رسد اما روش Fly را برای پرتاب NotSupportedException لغو می کند زیرا شترمرغ نمی تواند پرواز کند.
هنگامی که یک شترمرغ را نمونه می کنید و آن را به مرجع پرنده اختصاص می دهید، فراخوانی متد Fly منجر به یک استثنا می شود. این امر LSP را نقض می کند زیرا جایگزینی یک شترمرغ به جای پرنده رفتار مورد انتظار را تغییر می دهد و برنامه را نادرست می کند.
پایبندی به LSP
برای پایبندی به LSP، باید اطمینان حاصل کنیم که جایگزین کردن یک کلاس فرعی با یک سوپرکلاس، برنامه را خراب نمی کند. یکی از راههای رسیدن به این هدف، ایجاد سلسله مراتب کلاسی مناسبتر یا استفاده از رابطها برای نمایش رفتارهای مختلف است.
مرحله 1. یک رابط برای پرندگان تعریف کنید.
ابتدا یک رابط IBird تعریف می کنیم که نشان دهنده رفتار مشترک همه پرندگان است.
public interface IBird
{
void Move();
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
مرحله 2. اجرای کلاس های خاص پرندگان
در مرحله بعد، کلاسهای پرنده خاصی را پیادهسازی میکنیم که به رابط IBird پایبند هستند. هر کلاس پیاده سازی خاص خود را از متد Move خواهد داشت که رفتار حرکتی خاص پرنده را در بر می گیرد.
کلاس پرواز پرنده
public class FlyingBird : IBird
{
public void Move()
{
Fly();
}
public virtual void Fly()
{
Console.WriteLine(“Flying”);
}
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
کلاس FlyingBird رابط IBird را پیاده سازی می کند و یک متد Fly ارائه می دهد. متد Move به نام متد Fly، نشان دهنده رفتار پرواز است.
کلاس شترمرغ
public class Ostrich : IBird
{
public void Move()
{
Run();
}
public void Run()
{
Console.WriteLine(“Running”);
}
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
کلاس Ostrich نیز رابط IBird را پیاده سازی می کند اما یک متد Run به جای Fly ارائه می دهد. متد Move متد Run نامیده می شود که نشان دهنده رفتار در حال اجرا است.
مرحله 3. از کلاس های پرندگان استفاده کنید.
اکنون می توانیم از این کلاس های پرنده در برنامه خود بدون نقض LSP استفاده کنیم.
public class Program
{
public static void Main()
{
IBird bird1 = new FlyingBird();
bird1.Move(); // Outputs: Flying
IBird bird2 = new Ostrich();
bird2.Move(); // Outputs: Running
}
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
در این نسخه بازسازی شده
FlyingBird و Ostrich هر دو رابط IBird را پیاده سازی می کنند.
متد Move در هر کلاس رفتار حرکتی خاص پرنده را در بر می گیرد.
فراخوانی Move در یک نمونه از FlyingBird به “Flying” و فراخوانی Move روی یک نمونه از Ostrich منجر به “Running” می شود.
نتیجه گیری
با بازفرآوری کد اصلی برای پایبندی به اصل جایگزینی لیسکوف، اطمینان حاصل می کنیم که جایگزین کردن کلاس های فرعی برای کلاس پایه برنامه را خراب نمی کند. این باعث می شود کد ما قوی تر، قابل نگهداری و مقیاس پذیرتر باشد.
خلاصه
کد اصلی LSP را نقض می کند زیرا جایگزینی یک شترمرغ به جای یک پرنده باعث استثنا شد.
ما یک رابط IBird را برای نشان دادن رفتار رایج پرنده معرفی کردیم.
ما کلاسهای پرنده خاصی (FlyingBird و Ostrich) ایجاد کردیم که رابط IBrd را پیادهسازی کرده و رفتارهای مربوط به آنها را کپسوله میکردند.
این رویکرد تضمین می کند که برنامه ما بدون توجه به نوع خاص پرنده مورد استفاده، به درستی رفتار می کند.
با پیروی از اصل جایگزینی Liskov، طراحی و قابلیت اطمینان نرمافزار خود را بهبود میبخشیم و درک، گسترش و نگهداری آن را آسانتر میکنیم.
اصل جایگزینی لیسکوف (LSP) یکی از پنج اصل جامد طراحی شی گرا است.
“اشیاء در یک برنامه باید با نمونه هایی از انواع فرعی خود بدون تغییر در صحت آن برنامه قابل تعویض باشند.”
به عبارت ساده تر، اگر یک کلاس پایه (یا رابط) و یک کلاس مشتق شده دارید، باید بتوانید کلاس پایه را با کلاس مشتق شده جایگزین کنید بدون اینکه خطا یا تغییر رفتار مورد انتظار برنامه را ایجاد کنید.
📌کاوش بیشتر در: https://dotnet-fullstack-dev.blogspot.com/
🌟 اشتراک گذاری قدردانی می شود! 🚀
کد مشکل
بیایید با مثالی شروع کنیم که LSP را نقض می کند. یک کلاس پایه Bird و یک کلاس مشتق شده از Ostrich را در نظر بگیرید.
public class Bird
{
public virtual void Fly()
{
Console.WriteLine("Flying");
}
}
public class Ostrich : Bird
{
public override void Fly()
{
throw new NotSupportedException("Ostriches can't fly");
}
}
public class Program
{
public static void Main()
{
Bird bird = new Ostrich();
bird.Fly(); // Throws NotSupportedException
}
}
در این مثال،
- کلاس Bird یک متد Fly دارد که “Flying” را چاپ می کند.
- کلاس Ostrich از Bird به ارث می رسد اما روش Fly را برای پرتاب NotSupportedException لغو می کند زیرا شترمرغ نمی تواند پرواز کند.
هنگامی که یک شترمرغ را نمونه می کنید و آن را به مرجع پرنده اختصاص می دهید، فراخوانی متد Fly منجر به یک استثنا می شود. این امر LSP را نقض می کند زیرا جایگزینی یک شترمرغ به جای پرنده رفتار مورد انتظار را تغییر می دهد و برنامه را نادرست می کند.
پایبندی به LSP
برای پایبندی به LSP، باید اطمینان حاصل کنیم که جایگزین کردن یک کلاس فرعی با یک سوپرکلاس، برنامه را خراب نمی کند. یکی از راههای رسیدن به این هدف، ایجاد سلسله مراتب کلاسی مناسبتر یا استفاده از رابطها برای نمایش رفتارهای مختلف است.
مرحله 1. یک رابط برای پرندگان تعریف کنید.
ابتدا یک رابط IBird تعریف می کنیم که نشان دهنده رفتار مشترک همه پرندگان است.
public interface IBird
{
void Move();
}
مرحله 2. اجرای کلاس های خاص پرندگان
در مرحله بعد، کلاسهای پرنده خاصی را پیادهسازی میکنیم که به رابط IBird پایبند هستند. هر کلاس پیاده سازی خاص خود را از متد Move خواهد داشت که رفتار حرکتی خاص پرنده را در بر می گیرد.
کلاس پرواز پرنده
public class FlyingBird : IBird
{
public void Move()
{
Fly();
}
public virtual void Fly()
{
Console.WriteLine("Flying");
}
}
کلاس FlyingBird رابط IBird را پیاده سازی می کند و یک متد Fly ارائه می دهد. متد Move به نام متد Fly، نشان دهنده رفتار پرواز است.
کلاس شترمرغ
public class Ostrich : IBird
{
public void Move()
{
Run();
}
public void Run()
{
Console.WriteLine("Running");
}
}
کلاس Ostrich نیز رابط IBird را پیاده سازی می کند اما یک متد Run به جای Fly ارائه می دهد. متد Move متد Run نامیده می شود که نشان دهنده رفتار در حال اجرا است.
مرحله 3. از کلاس های پرندگان استفاده کنید.
اکنون می توانیم از این کلاس های پرنده در برنامه خود بدون نقض LSP استفاده کنیم.
public class Program
{
public static void Main()
{
IBird bird1 = new FlyingBird();
bird1.Move(); // Outputs: Flying
IBird bird2 = new Ostrich();
bird2.Move(); // Outputs: Running
}
}
در این نسخه بازسازی شده
- FlyingBird و Ostrich هر دو رابط IBird را پیاده سازی می کنند.
- متد Move در هر کلاس رفتار حرکتی خاص پرنده را در بر می گیرد.
- فراخوانی Move در یک نمونه از FlyingBird به “Flying” و فراخوانی Move روی یک نمونه از Ostrich منجر به “Running” می شود.
نتیجه گیری
با بازفرآوری کد اصلی برای پایبندی به اصل جایگزینی لیسکوف، اطمینان حاصل می کنیم که جایگزین کردن کلاس های فرعی برای کلاس پایه برنامه را خراب نمی کند. این باعث می شود کد ما قوی تر، قابل نگهداری و مقیاس پذیرتر باشد.
خلاصه
- کد اصلی LSP را نقض می کند زیرا جایگزینی یک شترمرغ به جای یک پرنده باعث استثنا شد.
- ما یک رابط IBird را برای نشان دادن رفتار رایج پرنده معرفی کردیم.
- ما کلاسهای پرنده خاصی (FlyingBird و Ostrich) ایجاد کردیم که رابط IBrd را پیادهسازی کرده و رفتارهای مربوط به آنها را کپسوله میکردند.
- این رویکرد تضمین می کند که برنامه ما بدون توجه به نوع خاص پرنده مورد استفاده، به درستی رفتار می کند.
با پیروی از اصل جایگزینی Liskov، طراحی و قابلیت اطمینان نرمافزار خود را بهبود میبخشیم و درک، گسترش و نگهداری آن را آسانتر میکنیم.