دانستنی‌ها

کلاس های مهر و موم شده در جاوا

در این مطلب با قابلیت جدید sealed class در جاوا آشنا می‌شویم.

هدف اصلی از وراثت در جاوا استفاده دوباره از کد (code reuse) است. با این امکان کلاس‌های متعدد می‌توانند از کلاس دیگر ارث‌بری کنند و از متد‌های از قبل تعریف‌شدهٔ آن برای خودشان استفاده کنند یا آن‌‌ها را گسترش دهند. هدف مهم دیگر (که با هدف اول هم چندان بی‌ربط نیست) این است که مدل و سلسله مراتبی برای درک بهتر پروژه طراحی شود. حالا با امکان «کلاس‌های مهر و موم شده» با محدود کردن این‌که چه کلاسی می‌تواند از کلاس ما ارث بری کند، طراحی به این مدل را کامل‌تر و پر معناتر می‌کند.

امکانات نسخه‌های پیشین برای کنترل ارث‌بری

با ابزارهای نسخه‌های پیشین جاوا هم می‌توان ارث‌بری را محدود کرد. مثلا می‌توانید کلاس مورد نظر را با دسترسی package یا private تعریف کرد تا فقط کلاس‌هایی که خودمان تعریف می‌کنیم بتوانند از آن ارث‌بری کنند. در این حالت سوپر کلاس را package access یا private تعریف کرده و کلاس‌های فرزند را به صورت public تعریف می‌کنمد.

مثالی از این حالت، کلاس AbstractStringBuilder است که در کتابخانه استاندارد تعریف شده تا سوپرکلاسی برای StringBuilder و StringBuffer باشد و متد append را برای هر دوی آن‌ها به ارث گذاشته تا از آن استفاده کنند.

همان طور که می‌بینید وقتی هدفمان استفاده دوباره از کد باشد، این روش به کارمان می‌آید ولی با این کار معنای انتزاع و همین‌طور امکانات چند ریختی را از دست می‌دهیم. همچنین نمی‌توانیم دیگر از اشیا سوپرکلاس استفاده کرده و روی نوع آن switch بزنیم. (این امکان در نسخه‌های آینده جاوا اضافه می‌شود و در ادامه همین مطلب معرفی می‌شود.)

یک راه دیگر برای محدود کردن ارث بری می تواند این باشد که کلاس را final تعریف کنیم که در این حالت به هیچ صورت نمی‌توانیم از کلاس ارث بری کنیم.

راه حل : کلاس های مهر و موم شده

از جاوا ۱۵ به بعد می‌توانیم کلاس‌های مهر و موم شده (sealed) تعریف کنیم. این نوع از کلاس‌ها نیازی که در بالا گفته شد را بر طرف می‌کنند. با یک مثال می خواهیم این نیاز را به طور دقیق‌تر مطرح کنیم و کاربرد کلاس های مهر و موم شده را در حل آن توضیح دهیم.

فرض کنید یک کلاس وسیله نقلیه (Vehicle) داریم. می خواهیم برای آن دو زیر کلاس وسیله نقلیه موتوری (MotorizedVehicle) و غیر موتوری (NonMotorizedVehicle) تعریف کنیم و در عین حال اجازه ندهیم هیچ کلاس دیگری از آن ارث بری کند. چون غیر از این هیچ دسته بندی دیگری برای وسایل نقلیه نداریم و این محدودیت ارث‌بری معنای مدل را کامل‌تر می کند. برای تعریف کلاس مهر و موم شده از کلمه کلیدی sealed استفاده می کنیم.

کلاس‌های مهر و موم شده باید زیرکلاس داشته باشند و گرنه خطای کامپایل به وجود می‌آید. زیرکلاس‌های آ‌ن‌را بعد از کلمهٔ کلیدی permits لیست می‌کنیم. اگر این کلاس‌ها در یک پکیج نباشند باید نام کامل آنها (مثل com.example.MotorizedVehicle) را بیاورید. حال دو کلاس MotorizedVehicle و NonMotorizedVehicle را تعریف می‌کنیم. اگر کلاسی از یک sealed کلاس ارث‌بری کند حتما باید یکی از سه کلمه کلیدی final یا sealed یا non-sealed را در امضای خود استفاده کند. اگر از کلمه کلیدی non-sealed استفاده کنیم دیگر محدودیتی برای ارث‌بری از آن کلاس وجود ندارد.

کلاس NonMotorizedVehicle را هم به صورت sealed تعریف می‌کنیم. چون نمی‌خواهیم از آن هم ارث‌بری دیگری انجام شود.

برای سادگی، دو زیر کلاس Bicycle و Sleigh برای NonMotorizedVehicle تعریف می‌کنیم و هر دو را به صورت final قرار می دهیم.

حالا دیگر از زیر شاخه NonMotorizedVehicle نمی‌توانیم هیچ‌گونه ارث بری‌ای انجام دهیم.

اکنون کلاس MotorizedVehicle را به گونه ای تعریف می‌کنیم که فقط دو زیر کلاس ماشین و کامیون داشته‌باشد.

چون کلاس Car می تواند انواع بسیار مختلفی داشته باشد, می خواهیم آنرا non-sealed تعریف کنیم تا کاربر بتواند از آن ارث بری کند و بر حسب نیاز خود به آن ویژگی های مورد نیاز خود را اضافه کند:

 

یادتان باشد در این حالت کاربر فقط از کلاس Car می تواند ارث‌بری کند و نه کلاس MotorizedVehicle.

کلاس Truck را هم برای سادگی دوباره final تعریف می‌کنیم تا کار تمام شود.

سلسله مراتب کلی این کلاس ها را در این شکل می‌توانید ببینید:

سلسله مراتب کلاس‌های این مثال

همچنین لازم به ذکر است که معنی sealed در C# همان final در جاوا است و نباید با آن اشتباه گرفته شود.

کلمه کلیدی sealed برای واسط ها هم به کار می رود. فقط به یاد داشته باشید اگر واسطی مهر و موم شده باشد هم واسط‌هایی که از آن ارث بری می‌کنند را محدود می‌کند و هم کلاس‌هایی که آن‌را پیاده‌سازی می‌کنند.

در پی این تغییر متدهای زیر به کلاس Class اضافه شده‌اند:

boolean isSealed() : اگر کلاس به صورت مهر و موم شده تعریف‌شده باشد true برمی‌گرداند در غیر این صورت false.

java.lang.constant.ClassDesc[] getPermittedSubclasses() : آرایه‌ای از اشیا ClassDesc را برمی‌گرداند که نشان‌دهنده همه اشیایی هستند که که این کلاس به آ‌ن‌ها اجازه ارث‌بری داده‌است. اگر کلاس sealed نباشد null برمی‌گداند.

سخن آخر

کلاس‌های مهر و موم شده مهم ترین تغییر جاوا ۱۵ بوده‌است که امکانات شی‌گرایی جاوا را بسیار بهتر کرده‌است. برای دیدن توضیح رسمی آن به JEP 360 مراجعه کنید. با اضافه شدن این امکان به جرأت می‌توان گفت جاوا شی‌گرا ترین زبان برنامه‌نویسی موجود است. برای تکمیل این امکان قرار است امکان switch زدن روی نوع کلاس اشیا هم به جاوا اضافه شود. البته قول این امکان به همراه pattern matching مدت زیادی است که به برنامه نویس ها داده شده ولی هنوز به صورت رسمی به جاوا اضافه نشده‌اند.

[تعداد: 2   میانگین: 3/5]
برچسب ها
نمایش بیشتر

نوشته های مشابه

یک نظر

  1. سرعت پیشرفت جاوا خنده داره. واقعا درک نمیکنم اوراکل هدفش چیه. خیلی از امکانات مهم و اصلی رو خیلی دیر پیاده سازی میکنه یا اصلا بیخیالش میشه (مثل method overloading). یا مثلا همین pattern matching که گفتید خیلی وقته زبانای دیگه اضافش کردن.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا