آموزش قدم به قدم جاوا – قسمت هفدهم – بخش اول

وراثت (Inheritance)

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

مثال: فرض کنید می‌خواهیم در برنامه خود دو کلاس به نام‌های Clerk (منشی) و Accountant (حسابدار) داشته باشیم. این دو کلاس را به صورت زیر طراحی کردیم:

در کلاس حسابدار فیلدها و متدهای زیر را داریم:

فیلدها: نام، حقوق، تاریخ استخدام و میزان ساعات کاری

متدها: دریافت نام و تاریخ استخدام

در کلاس منشی:

فیلدها: نام، حقوق و تاریخ استخدام

متدها: دریافت نام و تاریخ استخدام

همانطور که دیدید فیلدها و متدهای هر دو کلاس با هم مشترک هستند (به غیر از فیلد ساعات کاری کلاس حسابدار). ما با طراحی کلاس‌ها با این روش موجب افزونگی کد شدیم. روش بهتر ایجاد یک کلاس جدید است که شامل این فیلدها و متدهای مشترک باشد و این دو کلاس از آن کلاس ارث بری داشته باشند.

رابطه Is-A

یکی از نکات مهم، تشخیص‌دادن وراثت است و این‌که چه زمان می‌توان از وراثت استفاده کرد یا چه کلاس‌هایی می‌توانند از یکدیگر ارث‌بری داشته باشند. اگر بین دو کلاس رابطه Is-A (هست یک) وجود داشته باشد آنگاه می‌توان بین دو کلاس رابطه وراثت برقرار کرد.

مثلا حسابدار یک کارمند است. منشی یک کارمند است.

کامیون یک وسیله نقلیه است. موتورسیکلت یک وسیله نقلیه است.

البته باید توجه داشت که رابطه Is-A معمولا یک‌طرفه است. یعنی نمی‌توان گفت کارمند یک حسابدار است چون هر کارمند الزاما یک حسابدار نیست اما هر حسابدار یک کارمند بشمار می‌رود.

 

به شکل زیر دقت کنید:

ji1

کلاسی به نام Employee (کارمند) ایجاد کردیم. کلاس‌های Clerk و Accountant هر دو از کلاس Employee ارث‌بری خواهند داشت. منشی و حسابدار هر دو کارمند به حساب می‌آیند و بین این دو کلاس با کلاس Employee یک رابطه Is-A برقرار است.

کلاس Employee:

کلاس Accountant:

کلاس Clerk:

همانطور که می‌بینید اعضای مشترک دو کلاس Clerk و Accountant را حذف کرده و در کلاس Employee قرار دادیم.

تعیین‌کننده دسترسی فیلدهای مشترک این دو کلاس را از private به protected تغییر دادیم. دلیل این کار را به زودی خواهید فهمید.

کلاس‌های Clerk و Accountant با استفاده از کلمه کلیدی extends از کلاس Employee ارث‌بری دارند.

بدنه کلاس Clerk خالی است چون تمام اعضایی که کلاس Clerk داشت در کلاس Employee وجود دارد اما فیلد workingHours که مخصوص کلاس Accountant بود اکنون تنها فیلد موجود در کلاس Accountant است و بقیه اعضای خود را از Employee به ارث می‌برد.

نکته: به کلاسی که کلاس‌های دیگر از آن ارث‌بری دارند Superclass و به کلاس‌هایی که از Superclass ارث بری دارند Subclass گفته می‌شود. در فارسی معمولا به Superclass کلاس پدر و به Subclass کلاس فرزند می‌گویند.

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

حال می‌خواهیم متدی به کلاس Clerk اضافه کنیم که پارامتری با عنوان tax (درصد مالیات) دریافت کرده و حقوق ماهیانه منشی را با کم کردن مالیات به ما بر‌می‌گرداند. همچنین متد دیگری به این کلاس اضافه خواهیم کرد که اطلاعات منشی (نام و میزان حقوق) را برای ما نمایش دهد:

در متد getSalary از فیلد salary استفاده کردیم در صورتی که این فیلد ظاهرا در کلاس Clerk وجود ندارد اما چون این کلاس از Employee ارث‌بری دارد می‌تواند از فیلدها و متدهای آن مستقیما استفاده کند. به عبارت دیگر تمام اعضای کلاس Employee در کلاس Clerk هم وجود دارند.

در متد showInfo نیز از متد getName که در کلاس Employee وجود دارد استفاده کردیم.

حال می‌خواهیم در کلاسی دیگر شیئی از کلاس Clerk ایجاد کنیم و از متدهای آن استفاده کنیم. برای این کار ابتدا سازنده زیر را به کلاس Clerk اضافه می‌کنیم:

سپس در کلاسی که متد main در آن قرار دارد کدهای زیر را می‌نویسیم:

تعیین‌کننده‌های دسترسی و وراثت

اگر در کلاس‌های Clerk و Accountant می‌توانستیم از فیلدها و متدهای کلاس‌های Employee استفاده کنیم به این دلیل بود آن فیلدها و متدها به صورت protected و public تعریف شده بودند.

جدول زیر از قسمت تعیین کننده‌های دسترسی را به یاد می‌آورید:

کل برنامه

کلاس‌های وارث

پکیج

داخل کلاس

تعیین کننده دسترسی

*

*

*

*

public

*

*

package-private

*

private

*

*

*

protected

همانطور که در جدول مشخص است اگر اعضای یک کلاس پدر از نوع package-private یا private باشند نمی‌توان از آن‌ها در کلاس‌های فرزند آن استفاده کرد و از دید کلاس فرزند مخفی هستند. البته این به این معنی نیست که این اعضای مخفی در اشیا ساخته شده از کلاس فرزند وجود ندارند فقط فرق آن‌ها با اعضای public و protected این است که نمی‌توان در کلاس فرزند به آن‌ها دسترسی داشت.

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

چون فیلد int در کلاس اول private است پس نمی‌توان در کلاس B با نوشتن نام فیلد id به آن دسترسی داشت. اما اگر شیئی از کلاس B بسازیم می‌توانیم با فراخوانی متد getId مقدار آن را بگیریم. پس فیلد id اگرچه در کدنویسی از دید کلاس B مخفی است اما در اشیا ساخته شده از آن به صورت ضمنی وجود دارد.

مصطفی نصیری

دانشجوی نرم افزار هستم و علاقه شدیدی به برنامه نویسی مخصوصا با زبان جاوا دارم! در حال حاضر تمرکزم روی اندرویده. دوست دارم چیزایی که یاد میگیرم رو با بقیه به اشتراک بگذارم :)

همچنین ممکن است دوست داشته باشید ...

۱۳ واکنش

  1. بنظر من یکی از تفاوت های برنامه نویس حرفه ای و معمولی در استفاده از همین نکات و بهینه کردن کدهای نوشته شده است.

  2. سعید گفت:

    با سلام و خسته نباشید
    در کد اول این صفحه منظور از :
    private Date hireDate
    چیه؟
    hireDate متغیری از جنس متد Date هستش؟

    • مصطفی نصیری گفت:

      با سلام
      خیر Date متد نیست. Date یک کلاس است و از طریق اشیا ساخته شده از این کلاس می توان به اطلاعات تاریخ و زمان دسترسی داشت. در این کد متغیری از جنس کلاس Date به نام hireDate نوشتیم که به این متغیر می توان یک شی ساخته شده از کلاس Date را نسبت داد. اگر مطلب را تا آخر مطالعه کنید متوجه خواهید شد.
      موفق باشید

      • سعید گفت:

        ضمن تشکر
        پس چرا موقع تعریف Date قبلش class نذاشتیم؟
        مگر اینکه از Composition استفاده کرده باشیم یعنی قبلش Date تعریف شده
        درسته؟

        • مصطفی نصیری گفت:

          بله دقیقا. ببینید کلاس Date در پکیج java.util قرار داره که برای کار با تاریخ و زمان به کار میره. کوتاهی از من بود که به این نکته در ابتدا اشاره نکردم. برای استفاده از این کلاس باید این کلاس رو به صورت زیر import کنید:
          import java.util.Date;

  3. سعید گفت:

    خیلی ممنون
    امیدوارم ادامه بدین
    خیلی استفاده بردم تا حالا

  4. afshin گفت:

    سلام
    مرسی از اموزش خوبتون
    فقط من یه چیزی رو متوجه نشدم :
    در بخش محاسبه حقوق منشی داخل متد showInfo اومدین از متد getName استفاده کردین در صورتی فیلد Name از کلاس Employee ارث بری شده و ما میتونیم به طور مستقیم از این فیلد در این کلاس استفاده کنیم ( البته اگه اشتباه نکرده باشم !!!)
    چرا شما مستقیما از این فیلد استفاده نکردین ( در صورتی که در این کدها کلاسی وجود نداره که دسترسی به فیلد Name نداشته باشه و بخایم از متد استفاده کنیم ) ؟؟؟

    • مصطفی نصیری گفت:

      درسته چون دسترسی فیلد name به صورت protected تعریف شده میتونستیم به جای فراخوانی متد getName مستقیما از خود فیلد name استفاده کنیم و تنها دلیل اینکه متد getName را فراخوانی کردیم برای نشون دادن این بود که در کلاس های فرزند میشه از متدهای کلاس پدر استفاده کرد.

      اما توجه داشته باشید که اگر تعیین کننده دسترسی فیلد name در کلاس Employee برابر با private بود اونوقت نمی تونستیم مستقیما به فیلد دسترسی داشته باشیم و حتما باید با فراخوانی متد getName مقدار name را به دست می آوردیم.

      موفق باشید

      • afshin گفت:

        مرسی از توضیحتون . یه پیشنهاد ه داشتم :
        کاش بعد از هر بخش چن تا تمرین هم میذاشتین حالابا جواب یا بدون جواب چون واقعا بدون تمرین برنامه نویسی هیچی نیس و اگه بخایم هم داخل کتابا دنبال تمرین باشیم ممکنه سرفصل های اونا کمتر یا بیشتر از توضیح شما باشه و شاید زیاد جالب نباشه
        به هر حال مطالبتون عالیه و جای تقدیر داره
        موفق باشید

  5. nooshin گفت:

    با سلام ، از آموزش کامل و جامعتون واقعا ممنونم . من تازه برنامه نویسی جاوا را شروع کردم و بیشتر روی سرویس ها میخوام یاد بگیرم . تا اونجایی که میدونم در سرویس ها نمی توانیم فیلدی را تعریف کنیم اگر من قرار باشه از interface استفاده کنم چه جوری میتونم از این کدها استفاده کنم ؟ به عنوان مثال بخوام کارمندانی که حقوق ثابت میگیرن ، کارمندانی که ساعتی حقوق میگیرند را چگونه می تونم در قالب سرویس براشون متد بنویسم ؟ ممنون میشم اگر منو راهنمایی کنید .

    • مصطفی نصیری گفت:

      سلام. منظورتون از سرویس رو متوجه نشدم لطفا واضح تر بگید. درباره اینترفیس ها هم یک مطلب کامل در همین مجموعه آموزشی وجود داره میتونید استفاده کنید.

  6. اکبر بیرام زاده گفت:

    سلام خسته نباشید
    در قسمت ساخت شی از کلاس clerk
    تو پارامتر دوم که متغیر از جنس Date بود چرا new Date گذاشتید؟

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

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