آموزش جاوا، فصل یازدهم: ساختار کلاس ها در جاوا

همانطور که در فصل قبل گفتیم کلاس ها سنگ بنای برنامه نویسی شی گرا هستند. یک برنامه جاوا از تعدادی کلاس ساخته می شود. اشیا از روی کلاس ها ساخته می شوند و ارتباط اشیا با هم مسأله را حل می کند. حالا اگر قدری دقیق تر به کلاس ها نگاه کنیم، می بینیم که خود کلاس ها از اجزای کوچکتری ساخته می شوند. بار دیگر به ویژگی های برنامه های شی گرا از دید Alan Kay دقت کنید:

  1. هر چیزی یک شی است.
  2. یک برنامه مجموعه‌ای از اشیا است که با استفاده پیام‌رسانی به یکدیگر می‌گویند که چه کار باید بکنند.
  3. هر شیء‌ای دارای حافظه‌ای است که از سایر اشیا ساخته شده است.
  4. هر شیء‌ای یک «نوع» دارد.
  5. تمام اشیای همنوع می‌توانند پیام‌های یکسانی دریافت کنند.

قانون شماره ۱ می گوید هر چیزی یک شی است. این «هر چیزی» شامل متغیرها، اشیای ساخته شده از سایر کلاسها، و کلاً هر چیزی که در برنامه وجود دارد است. از آنجایی که هر شی از روی یک کلاس ساخته می شود، ارتباط تنگاتنگی بین ویژگی های اشیا و کلاس ها وجود دارد. به بیان ساده تر اگر چیزی در اشیا باشد، باید آن را در کلاس به نحوی بیان کرد.

اگر به قانون شماره ۳ دقت کنید، می بینید که به صراحت می گوید هر شی از سایر اشیا ساخته شده است. به یک ماشین نگاه کنید. از دور فقط یک ماشین می بینید ولی وقتی نزدیک تر می شوید، اجزای متفاوت تسکیل دهنده ماشین را می بینید. چرخ ها، درها، آینه های بغل و … اشیا هم همین طورند. وقتی با دقت بیشتر به اشیا نگاه کنیم می بینیم که اشیا پیچیده جز ترکیبی از اشیای ساده تر که با هم هماهنگ شده اند تا یک کار خاص را ادامه بدهند نیستند. حال اگر همین طور ادامه بدهیم به کلاس های اصلی سازنده برنامه می رسیم. این کلاس ها خود از نوع داده های اولیه (که حالا می دانیم آنها هم شی هستند) تشکیل شده اند. این «حافظه ساخته شده از سایر اشیا» را اصطلاحاً ویژگی ها (Property) می نامیم.

قانون شماره ۵ می گوید که اشیای همنوع، پیام های یکسانی دریافت می کنند. اشیای همنوع اشیایی هستند که همگی از روی یک کلاس ساخته شده اند. برای مثال اگر «خودروی سواری» را به عنوان یک کلاس در نظر بگیریم، همه نمونه های «خودروهای سواری» که در خیابان می بینیم، اشیای ساخته شده از روی این کلاس هستند و «همنوع» اند.

قانون ۲ می گوید که اشیا با استفاده انتقال پیام (Message Passing) به هم می گویند که چه کار باید بکنند. فرض کنید شما می خواهید ماشین را روشن کنید. چه کار می کنید؟ سوییچ را در جای مخصوصش قرار می دهید و آن را می چرخانید. با این کار شما به ماشین «پیغام» می دهید که می خواهید آن را روشن کنید. پاسخ ماشین به پیغام شما می تواند حالت های متفاوتی داشته باشد: روشن شود یا در اثر بروز خطا پیغام مناسبی را به شما نشان دهد. برای انجام دادن کاری در یک سیستم شی گرا راهی جز انتقال پیام (Message Passing) بین اشیا وجود ندارد.

قانون شماره ۵ تاکید می کند که اشیای همنوع پیام های یکسانی دریافت می کنند یعنی چه؟ یعنی «کارهای یکسانی می توانند انجام دهند» که در برنامه نویسی شی گرا آن ها را «رفتار» (Method) می نامیم.

با توجه به توضیحات بالا، الان می دانید که یک شی از ویژگی ها (Properties) و رفتارها (Methods) تشکیل شده است و از آنجایی که کلاس ها قالب و الگویی برای اشیا هستند باید بتوان به نوعی ویژگی ها و رفتارها را در کلاس تعریف کرد.

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

نام آلبوم؟ نام خواننده؟ نام آهنگساز؟ نام ناشر؟ سال انتشار؟ شماره مجوز؟ نوازندگان؟

بله! درست حدس زدید. همه این ها می توانند ویژگی های یک آلبوم موسیقی باشند. بنابراین باید در کلاسی که برای «آلبوم موسیقی» می سازیم، همه این ویژگی ها را لحاظ کنیم.

حالا اگر بخواهیم این کلاس را در جاوا بسازیم چیزی شبیه این خواهد شد:

public class MusicAlbum {
    // Properties
    private String name;
    private String singer;
    private String composer;
    private Date publishDate;
}

احتمالاً الان بهتر می توانید تفاوت بین کلاس و شی را ببینید. کلاس MusicAlbum را که ساختیم حالا می توانیم از روی آن نمونه یا شی بسازیم:

  • نام آلبوم: دستان
  • نام خواننده: محمدرضا شجریان
  • نام آهنگساز: پرویز مشکاتیان

یک شی ساخته شده از کلاس MusicAlbum است و

  • نام آلبوم: گل صدبرگ
  • نام خواننده: شهرام ناظری
  • نام آهنگساز: جلال ذوالفنون

یک شی دیگر. ولی همانطور که می بینید هر دوی اینها ویژگی های مشترکی دارند. هر دو نام دارند، خواننده دارند، آهنگساز دارند و سال انتشار  و …

برای ساختن یک شی از روی یک کلاس جاوا از کلمه کلیدی new استفاده می‌کنیم:

MusicAlbum dastan = new MusicAlbum();
MusicAlbum golSadBarg = new MusicAlbum();

سطح دسترسی

در زبان جاوا چهار سطح دسترسی وجود دارد:

  • private: اگر یک ویژگی یا متد را private تعریف کنیم، دسترسی به آن ویژگی یا متد فقط و فقط در همان کلاس مجاز است و از بیرون کلاس به آن‌ها دسترسی نداریم و اصطلاحاً در بیرون از کلاس دیده نمی‌شوند.
  • protected: دسترسی به ویزگی‌ها و متدهای protected مخصوص همان کلاسی است که آن را تعریف کرده است و کلاس‌هایی که در سلسله مراتب ارث‌بری از آن کلاس ارث برده‌اند. درباره ارث‌بری بیشتر خواهم گفت.
  • default: اگر هیچ سطح دسترسی برای یک ویژگی یا متد تعریف نکنیم، سطح دسترسی پیش‌فرض به آن تعلق می‌گیرد. سطح دسترسی پیش‌فرض به یک ویژگی یا متد یعنی خود کلاس، همه کلاس‌هایی که با این کلاس در یک بسته یا پکیج قرار دارند و همه کلاس‌هایی که در سلسله مراتب ارث‌بری از آن کلاس ارث برده‌اند به این ویژگی یا متد دسترسی دارند.
  • public: دسترسی public یا عمومی یعنی دسترسی به این متد یا ویژگی هیچ محدودیتی ندارد و در خود کلاس، و در همه کلاس‌های دیگر همان بسته و در همه کلاس‌های بسته‌های دیگر به آن‌ها دسترسی خواهیم داشت.

در کلاس MusicAlbum همه ویژگی‌ها را با سطح دسترسی private تعریف کردیم و در بیرون از کلاس به آن‌ها دسترسی نخواهیم داشت. مشکلی که اینجا به وجود می‌آید این است که دیگر نمی‌توانیم مقدار آن‌ها را تغییر بدهیم یا بخوانیم چون هیچ در هیچ کلاس دیگری به این ویژگی‌ها دسترسی نداریم.

MusicAlbum dastan = new MusicAlbum();
dastan.name = "دستان"; // Error 

می‌توانیم همه این ویژگی‌ها را به صورت public تعریف کنیم تا از هر جایی بتوانیم آن‌ها را تغییر بدهیم یا مقدارشان را بخوانیم:

public class MusicAlbum {
    // Properties
    public String name;
}

// ~~~~~~~~~~~~~~~

MusicAlbum dastan = new MusicAlbum();
dastan.name = "dastan"; // خطا نیست ولی خطرناک است 

این روش خیلی ساده است اما برای برنامه بسیار خطرناک است چون هر کلاسی از هر جایی ممکن است مقدار ویژگی‌ها را تغییر دهد و باعث به وجود آمدن باگ در برنامه بشود. چاره کار استفاده از متدهای دسترسی (Access Method) است.

متدهای دسترسی

برای هر ویژگی می‌توان متدهایی نوشت که دسترسی به ویژگی را محدود و کنترل می‌کنند. این متدهای دسترسی در اغلب زبان‌های برنامه‌نویسی به اشکال مختلف وجود دارند. در جاوا این متدها را با نام‌های set و get می‌شناسیم. اگر یک ویژگی با اسم name داشته باشیم متدهای دسترسی setName و getName نامیده می‌شوند:

private String name;

public void setName(String s) {
     name = s;
}

public String getName() {
    return name;
}

مزیت مهم استفاده از متدهای دسترسی، امکان کنترل بیشتر در مواقع خواندن و نوشتن ویژگی‌ها است. برای مثال اگر یکی از ویژگی‌های کلاس یک عدد صحیح است که مقادیر مجاز آن فقط در محدوده ۱ تا ۱۰ است، می‌توان در زمان set کردن مقدار، این موضوع را بررسی کرد و اگر مقدار set شده در محدوده مجاز نبود خطا داد:

private int number;

public void setNumber(int i) {
     if(i < 1 && i > 10) {
          throw new Exception("Number is not in range 1 to 10")
     }
     number = i;
}

در مثال بالا اگر عدد در محدوده مجاز نباشد برنامه اصطلاحاً یک خطا پرتاب می‌کند و اجازه نمی‌دهد مقادیر غیر مجاز در ویژگی number قرار بگیرد.

نکته کاربردی: اگر تعداد ویژگی‌های یک کلاس زیاد باشد، ساخت تعداد زیادی متدهای دسترسی، کاری سخت است و احتمال بروز خطا در آن بسیار بالا است. همه IDE های برنامه‌نویسی جدید می‌توانند این متدها را به صورت خودکار بسازند.

متد سازنده

همانطور که دیدید در زمان ساخت اشیا از عملگر new استفاده کردیم. عملگر new یک متد خاص از کلاس را صدا می‌زند که هم اسم کلاس است. کار این متد ساختن یک شی از روی یک کلاس است. به این متد سازنده یا constructor می‌گوییم. متد سازنده می‌تواند مقادیری را بگیرد و شی را بر اساس آن مقادیر بسازد:

public class MusicAlbum {
    // Properties
    private String name;
    private String singer;
    private String composer;

    public MusicAlbum(String name, String singer, String composer, Date publishDate) {
         
    }
}

متد سازنده نوع بازگشتی ندارد و نام آن دقیقاً با کلاس یکی است.

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

public class MusicAlbum {
    // Properties
    private String name;
    private String singer;
    private String composer;

    public MusicAlbum() {
         // مقداردهی اولیه به شی      
    }

    public MusicAlbum(String name, String singer, String composer, Date publishDate) {
         // مقداردهی اولیه به شی       
    }
}

متد سازنده‌ای را که هیچ آرگومان ورودی ندارد، سازنده پیش‌فرض یا default constructor می‌گویند. اگر برای یک کلاس سازنده پیش‌فرض ننویسید کامپایلر جاوا در زمان کامپایل یک متد سازنده پیش‌فرض به کلاس اضافه می‌کند. این سازنده همان سازنده‌ای است که در زمان ساخت یک شی از روی کلاس MusicAlbum پیش از این از آن استفاده کردیم.

اشاره‌گر this

هر شی‌ای که در زبان جاوا ساخته می‌شود دارای یک اشاره‌گر است که با کلمه کلیدی this شناخته می‌شود. این اشاره‌گر در یک کلاس همواره به شی‌ای که از روی کلاس ساخته می‌شود اشاره می‌کند و از طریق آن می‌توان به ویژگی‌ها و متدها دسترسی داشت. یکی از کاربردهای this در زمانی است که بین آرگومان‌های یک متد و ویژگی‌های کلاس ابهام وجود دارد.

public class MusicAlbum {
    // Properties
    private String name;
    private String singer;
    private String composer;

    public MusicAlbum(String name, String singer, String composer, Date publishDate) {
         // مقداردهی اولیه به شی   
        name = name;    
    }
}

به مثال بالا دقت کنید. در آرگومان‌های متد سازنده یک ورودی به نام name داریم و در لیست ویژگی‌های کلاس هم یک ویژگی با نام name داریم که می‌خواهیم مقدار آن را set کنیم. در مثال بالا کامپایلر نمی‌تواند تشخیص بدهد که منظور ما از name در سمت چپ تساوی ویژگی name و در سمت راست تساوی آرگومان name است. برای رفع ابهام در این موارد از اشاره‌گر this استفاده می‌کنیم:

public class MusicAlbum {
    // Properties
    private String name;
    private String singer;
    private String composer;

    public MusicAlbum(String name, String singer, String composer, Date publishDate) {
         // مقداردهی اولیه به شی   
        this.name = name;    
    }
}

وقتی که از this استفاده می‌کنیم منظور ما ویژگی‌ها و متدهای کلاس هستند.

Facebooktwittergoogle_plusredditpinterestlinkedinmailFacebooktwittergoogle_plusredditpinterestlinkedinmail




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

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