بررسی انواع روش های ارث بری Prototypical , Classical

بررسی انواع روش های ارث بری Prototypical , Classical

ارث بری یکی از اصول مهم شی گرایی است که این قابلیت را به شی های ساخته شده از یک کلاس می دهد که Propertyها و Methodهای کلاس های دیگر را به خود بگیرند و با این کار قابلیت استفاده مجدد از کد یا Reusability انجام می گیرد.

فرض کنید میخواهیم یک فریم ورک GUI طراحی کنیم. در این فریم ورک، کلاسی هایی مانند TextBox, Button متصور هستند. همه این کلاس ها قابلیتی در خود دارند به نام Enable که بتوان آن ها را فعال و غیر فعال کرد. حالا در طی طراحی این فریم ورک به یک کنترل دیگری نیاز خواهیم داشت به اسم ListBox و این کنترل هم باید قابلیت فعال و غیر فعال شدن را داشته باشد. اگر فرض کنیم طریقه پیاده سازی این قابلیت در همه این کنترل ها به یک صورت باشد، ما نمی خواهیم این کار را در همه کلاس ها تکرار کنیم چون اگر باگی در پیاده سازی آن پیدا شد، مجبوریم این باگ را در جاهای مختلفی رفع کنیم و یا اگر بخواهیم تغییری در پیاده سازی این قابلیت بدهیم، مجبوریم این تغییرات را در کلاس های مختلفی اعمال کنیم. در اینجاست مفهومی به نام استفاده مجدد از کد می تواند این مشکلات را حل کند این تکنیک در دو فاز نگهداری و توسعه به کمک ما خواهد آمد. مفهوم ارث بری کردن نمونه ای از پیاده سازی این تکنیک در کدنویسی است. 

در واقع می توان کلاسی به نام Control داشت و تمام این مشخصات و رفتارهایی که در همه این کنترل ها یکسان است را درون آن قرار داد و کلاس های دیگر از آن ارث بری کنند تا این مشخصات و رفتارها به آن ها به ارث برسد. در زیر دیاگرام UML ارث بری را مشاهده می کنید.

در دنیای ارث بری به کلاس Control ، کلاس ‌‌Base یا Super یا Parent گفته می شود و به کلاس های TextBox , ListBox، کلاس Derived یا Sub یا Child گفته می شود و به رابطه ای که بین کلاس های Parent و Child ایجاد می شود رابطه IS-A گفته می شود یعنی TextBox IS-A Control به این معنی که هر TextBoxی یک کنترل است چون تمام خصوصیات و رفتارهای  Controlرا به ارث برده است.

تمام مواردی که در بالا توضیح داده شد ارث بری Classical بود این در حالی است که در بعضی از زبان های برنامه نویسی مانند JavaScript چیزی به نام کلاس وجود ندارد و در آنجا همه چیز شی است و تنها شی وجود دارد. در این نوع زبان ها یک نوع ارث بری دیگری وجود دارد به نام ارث بری Prototypical. در واقع دو نوع ارث بری وجود دارد Classical و Prototypical. 

حالا سوال این است در زبانی که کلاس در آن وجود ندارد و تنها با شی ها مواجه هستیم ارث بری را به چه طریقی می توان پیاده سازی کرد؟ برای جواب دادن به این سوال همان مثال قبل را در نظر بگیرید که یک شی TextBox داریم و یک شی Control. برای پیاده سازی کردن ارث بری از نوع Prototype بین این دو شی ابتدا همه رفتارها و قابلیت های عمومی را در شی Control قرار می دهیم مانند متد Enable. سپس یک لینک از شی TextBox به شی Control ایجاد می کنیم. با این کار به شی prototype، Control شی TextBox گفته می شود.

در واقع شی prototype شده یعنی شی Parent، Control شی TextBox محسوب می شود و به این طریق رابطه IS-A بین شی Control و شی TextBox ایجاد می شود. در زبان JavaScript همه شی ها (به جز شی Object که سرشاخه همه شی ها محسوب می شود) یک prototype دارند که Parent آن شی محسوب می شود و تمام خصوصیات و متدهای آن را به ارث می برند. 

در ادامه نمونه ای از پیاده سازی prototype را در زبان JavaScript میبینیم.

یک آبجکت خالی به نام x تعریف می کنیم. در تصویر زیرprototype یا parent شی x دیده می شود. همه شی هایی که در جاوااسکریپت تعریف می شوند فرزند مستقیم یا غیر مستقیم شی Object هستند. شی Object سرشاخه همه شی های جاوااسکریت است و خود این شی prototype یا parent ندارد. در این شی متدهایی مانند toString و hasOwnProperty و ... تعریف شده است که از طریق شی های دیگر قابل فراخوانی است. 

مثلا اگر متد toString را روی شی x فراخوانی کنیم با خروجی زیر روبرو می شویم چون پیاده سازی پیش فرضی در شی Object انجام شده است و البته می توان این پیاده سازی را در شی های مشتق شده از آن override کرد.

>> x.toString()

>> '[object Object]'

پس با تعریف کردن x، یک شی در حافظه ساخته می شود و این شی یک لینکی به شی دیگری در حافظه دارد به نام Object. پس شی x فرزند شی Object محسوب می شود یا به بیانی دیگر شی Object، prototype شی x است.

حالا اگر شی دیگری به نام y تعریف کنیم و آن را نمایش دهیم خواهیم دید که prototype این شی هم دقیقا همان شی Object خواهد بود. برای اینکه مطمئن شویم می توانیم دستور زیر را اجرا کنیم. متد getPrototypeOf شی Object، prototype شی داده شده را برمی گرداند. همانطور که می بینید true در خروجی دیده می شود که نشان می دهد prototype این دو تا شی یکسان است

>> Object.getPrototypeOf(x) === Object.getPrototypeOf(y)

>> true

اگر دقیق تر بررسی کنیم سوالی که اینجا مطرح می شود این است که وقتی متد toString که متعلق به شی Object است ولی بوسیله شی x که یک شی خالی است فراخوانی می شود چه اتفاقی بوسیله جاوااسکریپت رخ می دهد؟ وقتی یک متد یا پراپرتی را توسط شی ای فراخوانی میکنیم جاوااسکریپت ابتدا روی همان شی دنبال این متد یا پراپرتی می گردد. اگر آن را پیدا کرد همان را اجرا می کند و در غیر اینصورت روی شی prototype این شی دنبال آن می گردد. اگر آنجا پیدا شد همان را اجرا می کند و اگر آنجا هم پیدا نشد همین روال را ادامه می دهد تا به شی Object برسد و اگر آن جا هم نبود خطا می دهد. به طور کلی به این روال Prototypical Inheritance گفته می شود و این نکته را همیشه در نظر داشته باشد که prototype چیزی بیشتر از یک شی نیست.

از بهترین نوشته‌های کاربران سکان آکادمی در سکان پلاس


online-support-icon