🧩 وراثت و اینترفیسها در #C: بازپیادهسازی و الگوهای حرفهای
تو پست قبلی، وراثت و اینترفیسها رو جداگونه بررسی کردیم. اما وقتی این دو تا با هم ترکیب میشن، دنیایی از نکات ظریف و الگوهای پیشرفته به وجود میاد.
امروز میخوایم یاد بگیریم چطور یه عضو اینترفیس رو در سلسلهمراتب وراثت به درستی override کنیم.
1️⃣ روش استاندارد: virtual و override
به صورت پیشفرض، وقتی یه عضو اینترفیس رو پیادهسازی میکنید، اون sealed (مهر و موم شده) هست. برای اینکه به کلاسهای فرزند اجازه override کردنش رو بدید، باید اون رو صراحتاً virtual مشخص کنید. این کار به شما اجازه میده از قدرت کامل چندریختی (Polymorphism) استفاده کنید.
public interface IUndoable { void Undo(); }
public class TextBox : IUndoable
{
public virtual void Undo() => Console.WriteLine("TextBox.Undo");
}
public class RichTextBox : TextBox
{
public override void Undo() => Console.WriteLine("RichTextBox.Undo");
}
// --- نتایج ---
RichTextBox r = new RichTextBox();
r.Undo(); // RichTextBox.Undo
((IUndoable)r).Undo(); // RichTextBox.Undo
((TextBox)r).Undo(); // RichTextBox.Undo (رفتار یکپارچه و درست)2️⃣ تکنیک خطرناک: بازپیادهسازی
(Re-implementation) ⚠️
حالا فرض کنید کلاس پدر، متد رو virtual نکرده. یه راه برای "override" کردنش، بازپیادهسازی اینترفیس در کلاس فرزنده. این کار، پیادهسازی رو فقط وقتی که آبجکت از طریق خود اینترفیس صدا زده بشه، "هایجک" میکنه.
تلهی بزرگ: ☠️ اگه پیادهسازی در کلاس پدر به صورت ضمنی (public) باشه، این الگو باعث رفتار متناقض و خطرناک میشه!
public class TextBox : IUndoable
{
// این متد virtual نیست!
public void Undo() => Console.WriteLine("TextBox.Undo");
}
public class RichTextBox : TextBox, IUndoable // بازپیادهسازی اینترفیس
{
// اینجا new هم میتونستیم بذاریم
public void Undo() => Console.WriteLine("RichTextBox.Undo");
}
// --- نتایج متناقض و خطرناک ---
RichTextBox r = new RichTextBox();
r.Undo(); // RichTextBox.Undo
((IUndoable)r).Undo(); // RichTextBox.Undo (هایجک شد)
((TextBox)r).Undo(); // TextBox.Undo (فاجعه! رفتار چندریختی شکست)
3️⃣ الگوهای حرفهای (جایگزینهای بهتر) ✅
بازپیادهسازی معمولاً یه راه حل ضعیف و نشانهی طراحی بده. دو الگوی خیلی بهتر برای طراحی کلاسهای توسعهپذیر وجود داره:
الگوی اول: اگه پیادهسازی ضمنیه، همیشه virtual ـش کنید (همون روش شماره ۱).
الگوی دوم (برای پیادهسازی صریح): پیادهسازی صریح (explicit) اینترفیس رو به یک متد protected virtual وصل کنید. این الگو، قدرت کامل رو به کلاسهای فرزند میده تا رفتار رو به صورت امن override کنن.
public class TextBox : IUndoable
{
// پیادهسازی صریح، کار را به یک متد مجازی و محافظتشده میسپارد
void IUndoable.Undo() => Undo();
protected virtual void Undo() => Console.WriteLine("TextBox.Undo");
}
public class RichTextBox : TextBox
{
protected override void Undo() => Console.WriteLine("RichTextBox.Undo");
}
🤔 حرف حساب و تجربه شما
این الگوها، تفاوت بین یه کتابخونه قابل اعتماد و یه کتابخونه شکننده رو رقم میزنن. طراحی برای توسعهپذیری، نشانه یک معمار نرمافزار حرفهایه.
🔖 هشتگها:
#CSharp #DotNet #OOP #Interface #Inheritance