کلاس(Class) و اشیا (objects)
کلاس هسته اصلی جاوا است . کلاس همچنین شکل دهنده اساس برنامه نویسی شی گرا در جاوا می باشد .کلاس توصیف کننده ساختار و رفتاری داده و کد است که توسط یک مجموعه از اشیا اشاعه خواهد یافت
کلاس یک نوع جدید داده را تعریف می کند . هربار که برای یک شی این نوع تعریف شود ، می توان از آن برای ایجاد اشیائی از همان نوع استفاده نمود . بنابراین ، یک کلاس قالبی(template) از یک کلاس است . چون شی نمونه ای (instance) از یک کلاس است غالبا کلمات شی(object) و نمونه (instance) را به صورت مترادف بکار می بریم . هر شی در یک کلاس شامل ساختارو رفتار تعریف شده توسط همان کلاس است. بنابراین ، یک کلاس یک ساختار منطقی است ، یک شی دارای واقعیت فیزیکی است.
اعضای کلاس یا متغییر های عضو یا متغییر های نمونه:
متد ها و متغییرهای تعریف شده در داخل یک کلاس را ، اعضای یک کلاس (members) یا متغیرهای عضو(member variables) یا متغیرهای نمونه (instance variables) یک کلاس می نامند .کدی که روی آن داده ها عمل می کند را متدهای عضو (member methods) یا فقط متدها methods می نامند . اگر با C++ و C آشنا باشید می دانید که متد(methods) در بر نامه نویسی جاوا همان تابع (function) در زبانهای C++و Cمی باشدکلیه زبانهای برنامه نویسی شی گرا مکانیسمهایی را در اختیار شما قرار می دهند تا مدل شی گرا را پیاده سازی نمایید .
این مدل شامل کپسول سازی(encapsulation) ، وراثت (inheritance) و چند شکلی یا چند ریختی (polymorphism)
می باشد.
کپسول سازی (encapsulation):
کپسول سازی مکانیسمی است که یک کد و داده مربوط با آن کد را یکجا گرد آوری نموده(در یک کپسول فرضی قرار داده) و کپسول بدست آمده را در مقابل دخالت یا سو استفاده های غیر مجاز محافظت می نماید .کلاسهای فقط برای کپسول سازی متد main() استفاده می شد. در جاوا کپسول سازی بر اساس کلاس (class)انجام می گیرد. هر مفهومی که مایلید در یک برنامه جاوا پیاده سازی نمایید باید ابتدا داخل یک کلاس کپسول سازی شود.
می دانید که کپسول سازی ، داده ها را با کدی که با آن داده ها سر و کار دارد پیوند می دهد. اما کپسول سازی یک خصلت بسیار مهم دیگر دارد و آن هم کنترل دستیابی (access control) است. از طریق کپسول سازی ، می توانید کنترل کنید چه بخشهایی از یک برنامه می توانند به اعضای یک کلاس دسترسی داشته باشند . با کنترل نمودن دستیابی ، می توانید از سو استفاده جلوگیری نمایید.
سطوح دسترسی:
سه سطح دسترسی در جاوا داریم: public ،private و protectedPublic (عمومی) : اگر عضوی از کلاس را public تعریف کنیم، آن عضو توسط اعضای هر کلاس دیگری در برنامه قابل دسترسی خواهد بود.
Private (خصوصی) : اگر عضوی از کلاس را Private تعریف کنیم، آن عضو فقط توسط اعضای همان کلاس قابل استفاده خواهد بود. بنابراین هر کد دیگری که عضو یک کلاس نباشد، نمی تواند به یک متد خصوصی دسترسی داشته باشد.
Protected (محافظت شده) : زمانی استفاده می شود که وراثت وجود داشته باشد. در وراثت جابجا شود اما باز هم آبجکت به آن دسترسی نداشته باشد.
(برای همین همیشه قبل از main همیشه public قرار گرفته.)
(package ها (بسته ها) هم برای کپسوله سازی و کنترل دسترسی استفاده می شوند.)
کپسوله سازی متغییر، در بخش Refactor گفته شده است.
وراثت (inheritance) :
با استفاده از وراثت ، می توانید یک کلاس عمومی بسازید که ویژگیهای مشترک یک مجموعه اقلام بهم مرتبط را تعریف نماید . این کلاس بعدا ممکن است توسط سایر کلاسها به ارث برده شود و هر کلاس ارث برنده چیزهایی را که منحصر بفرد خودش باشد به آن اضافه نماید. کلاسی که بارث برده می شود را کلاس اصلی (superclass) می نامند و کلاسی که عمل ارث بری را انجام داده و ارث برده، را کلاس زیرشاخه (subclass) می نامند. بنابراین، کلاس زیرشاخه ، کلیه متغیرهای نمونه و متدهای تعریف شده توسط کلاس اصلی را به ارث برده و چیزهایی منحصر بفرد خود را نیز اضافه می کند. در واقع هدف اصلی وراثت کدنویسی کمتر است.گاهی اوقات ممکن است برخی از Object ها خصوصیاتشان مشابه برخی دیگر Object ها باشد و اگر برنامه نویس بخواهد تک تک این Object ها را ایجاد کند و خصوصیات یکسانشان را نیز برای هر کدام تعریف کند، اگر در حین نوشتن پروژه بخواهد تا تغییری در برخی خصوصیات Object ها اعمال کند، مجبور است تا کلیه Object ها را بازنویسی کند اینجا است که از وراثت استفاده می کند. تا دیگر مجبور نباشد در صورت بروز یک تغییر، کل خصوصیات و یا رفتارهای Object های ایجاد شده را بازنویسی کند.
وراثت امکان ایجاد طبقه بندی های سلسله مراتبی را بوجود می آورد.
وراثت سلسله مراتبی:
فرض کنیم که ما سه Object داریم به طوریکه Object B از Object A ارث بری می کند و Object C از Object B . در واقع Object C نه تنها از ویژگی های Object B برخوردار خواهد بود، بلکه از آنجا که Object B از Object A ارث بری می کند، Object C ویژگی های Object A را نیز در بر خواهدداشت. در این مثال Object A به عنوان Superclass یا "کلاس اصلی" تلقی می شود و Object B و Object C به عنوان Subclass یا "کلاس زیرشاخه" تلقی خواهند شد. جالب است بدانیم که در مثال فوق اگرچه که Object B برای Object A به عنوان یک Subclass تلقی می شود اما این در حالی است که برای Object C به عنوان یک Superclass مد نظر قرار داده می شود.انواع وراثت:
وراثت از یک کلاس اصلی میتواند عمومی، خصوصی یا حفاظت شده باشد. این تعیین سطح دسترسی، مشخص میسازد آیا کلاسهای نامربوط و یا مشتق شده میتوانند به اعضای عمومی یا حفاظت شده کلاس پایه دسترسی داشته باشند. تنها وراثت عمومی به معنای وراثت به کار رفته بصورت عموم است. دو نوع دیگر وراثت به ندرت مورد استفاده قرار میگیرند. کلاسهای پایه ممکن است بصورت مجازی تعریف شوند که به آن وراثت مجازی (Virtual Inheritance ) گویند. وراثت مجازی تضمین میکند که فقط یک نمونه از کلاس پایه وجود داشته باشد و مشکلاتی همانند مشکلات وراثت چندگانه Multiple Inheritance)) بوجود نیاید. در وراثت چندگانه امکان اشتقاق از چند کلاس پایه را فراهم مینماید که موجب بوجود آمدن گراف رابطه وراثت بسیار پیچیده است.تفاوت وراثت در java و C++
وراثت یک از اصول در زمینه برنامه نویسی شی گرا ( Object Oriented Programming) است و با وراثت در C++ تفاوت زیادی دارند.یکی از مهمترین آنها، وراثت چندگانه که در Java شما فقط از یک کلاس میتوانید ارث بری کنید ولی در C++ یک کلاس از چند کلاس میتواند ارث بری کند. (البته در Java میتوانید شبیه این کار رو با Interface انجام دهید)
یکی دیگر از اینها Operator Overloading و دیگر Virtual method است.
Generic به جاوا اضافه شده ولی قبلا نبود که همون Template در C++ است.
اکنون به بررسی یک مثال در Netbeans می پردازیم :
مثال ما یک دانشگاه است و فرض می کنیم موجودیتهایی به نام student ، teacher ، employee داریم.
اگر از وراثت استفاده نکنیم: وقتی شروع به کد نویسی می کنیم برای student ، نام، فامیل، id ، تلفن، آدرس، نام پدرو مشخصات زیادی به آن می دهیم مثلا 15 تا مشخصه ی public int یا public string می شود. اما ما هیچ وقت مشخصات را به صورت متغییر استفاده نمی کنیم و تبدیل به get وset می کنیم، به این دلیل که در متد set می توانیم آن مقدار را اعتبار سنجی وکنترل کنیم. اکنون با تبدیل شدن به get وset آن 15 خط به 30 خط تبدیل می شود که 30 خط برای student داریم. اما teacher تقریبا همین مشخصات را با چند تفاوت دارد. پس دوباره 30 خط برای این داریم. و همینطور employee هم این خط ها با چند تفاوت را دارد مثلا شماره استخدامی. پس می بینیم که یه سری کد را مرتب داریم تکرار می کنیم. برای رفع اینهمه تکرار از وراثت استفاده می کنیم.
( این سه موجودیت، هرسه دارای مشخصات ورفتارهای مشابه می باشد یعنی هر سه نام، فامیل، id ، تلفن، آدرس دارند و هرسه متد print و متدهای دیگری نیاز دارند. مشخصات مشترک را در کلاس جدیدی به نام کلاس اصلی یا پدرمی نویسیم وکلاس های دیگر (فرزند) را از آن مشتق می کنیم.)
پروژه ای به نام Inheritance ایجاد می کنیم و در آن کلاس human (کلاس پدر یا اصلی) ایجاد می کنیم و کلاسهای student و teacher را ایجاد و از آن مشتق می کنیم. در این صورت با نوشتن مشخصات و رفتارها در کلاس human ، به طور اتوماتیک سه کلاس دیگر که از آن مشتق شده اند این مشخصات و رفتارها را دارند:
public void print() { System.out.println("name: " + Name + "family: " + Family ) ;{
ابتدا به بررسی حالت های مختلف می پردازیم. در کلاس student مشخصه ی classversion را private تعریف می کنیم:
اینجا نیاز به حالت سوم داریم. به همین خاطر در کلاس human آن را protected تعریف می کنیم:
یعنی اگر main بخواهد از مشخصه ای که protected است و از کلاسی که آن را تعریف کرده ارث بری نمی کند، استفاده کند، دو حالت دارد:
1- اگر کلاس main با کلاسhuman در یک package باشند می تواند از مشخصه ی classversion استفاده کند:
برای نمونه ای که از کلاس student با نام st ، در کلاس main ساخته می شود، classversion را می آورد :
پکیج دیگری به نام inheritance2 ایجاد می کنیم و main را در آن قرار دهیم (از طریق : کلیک راست روی کلاس main و Refactor > Move و انتخاب پکیج inheritance2 )
با تایپ st ، مشخصه ی classversion را نمی آورد و اگر خودمان تایپ کنیم و اجرا کنیم، خطا می گیرد.
همانطورکه در شگل زیر می بینید در بخش output، قسمتی که در کادر قرمز نشان داده شده، بیان کرده که classversion ، protected است :
چند ریختی یا پلی مورفیسم (polymorphism):
چند ریختی یا چندشکلی یا پلی مورفیسم (Polymorphism) به این معنا است که عکس العمل های متفاوتی که زیر کلاس های یک کلاس، به یک رویداد واحد در کلاس پدرشان می توانند انجام دهند.چند ریختی، کپسول سازی و وراثت در تقابل با یکدیگر کار می کنند هنگامیکه مفاهیم چند ریختی ، کپسول سازی و وراثت را بطور موثری تلفیق نموده و برای تولید یک محیط برنامه نویسی بکار بریم ، آنگاه برنامه هایی غیر قابل قیاس نسبت به مدلهای رویه گرا خواهیم داشت .یک سلسله مراتب خوب طراحی شده ازکلاسها، پایه ای است برای استفاده مکرر از کدهایی که برای توسعه و آزمایش آنها وقت و تلاش زیادی صرف نموده اید . کپسول سازی به شما امکان می دهد تا کدهایی را که به رابط عمومی برای کلاسهای شما بستگی دارند ، بدون شکسته شدن برای پیاده سازیهای دیگر استفاده نمایید. چند ریختی به شما امکان می دهد تا کدهای تمیز قابل حس ، قابل خواندن و دارای قابلیت ارتجاعی ایجاد نمایید .
Polymorphism در بسیاری از زبانها مانند خانواده C و همچنین زبانهای متن بازی مانند java و php پیاده سازی شده است.
چند ریختی به سه طریق انجام می شود:
1- ad-hoc : این روش تغییر درسطح امضای متد ها یا عملگر ها می باشد که سربارگذاری(override) نام دارد:
مثلا در جاوا تقریبا همه ما از دستور زیر برای چاپ در کنسول استفاده کرده ایم:System.out.print(arg);
arg می توانید انواع مختلفی از جمله رشته یا عدد باشد و تنها به یک نوع خاص محدود نمی شود. این سربارگذاری تابع یا function overloading می باشد. یا مثلا در جاوا عملگر + هم برای عدد بکار می رود و هم برای رشته که این oprator overloading می باشد که هر دوی اینها از نوع ad-hoc polymorphism می باشد.
2- arametric : در حقیقت در این نوع یک قالب آماده از کلاس را داریم که با دریافت پارامتر می توان به آن شکل داد.
مفهوم Generics در اصل همان parametric polymorphism می باشد.برای مثال می توان لیست ها در جاوا را نام برد. که در هنگام ایجاد پارامتر را به آن می دهیم.
List<JavabYabUser> users;
3- : subtype در اینجا یک مثال استفاده می کنیم: موجودیت دانشجو و استاد همگی انسان هستند و خصیصه های یکسانی دارند،
این مشترکات را می توان در یک super class به اسم humanداشت و student و teacherهمگی subtype آن باشند.پروژه بخش وراثت را دنبال می کنیم که به نام Inheritance بوده و در آن کلاس human (کلاس پدر یا اصلی) و کلاسهای student و teacher را ایجاد و از آن مشتق کرده بودیم:
در متد main رفتار print را می بینیم، در کلاس human تعریف شده و از آن به ارث رسیده (در کلاس های student و teacher هم قابل دسترسی است). اگر در main از print استفاده کنیم نمی تواند number یا همان شماره انشجویی (که در کلاس studentتعریف شده) را چاپ کند:
در تصویر زیر در کلاس human یک دایره خاکستری (در کادر بنفش) در ستون سمت چپ، کنار متد print دیده می شود که با کلیک کردن آن پیغامی ظاهر می شود (در کادر قرمز) که می گوید این رفتارتوسط student و teacher، override شده است:
همانطور که گفته شد هدف اصلی وراثت کد نویسی کمتر است اما در اینجا کد نویسی بیشتر شد و print چند بار تعریف شده است.
همیشه کلاسهای والد و فدزند را خودمان تعریف نمی کنیم ، گاهی اوقات ما کلاس والد را از کامپایلر یا زبان می گیریم و آن را پلی مورفیسم می کنیم یا گاهی اوقات مدیر پروژه آن را می نویسد و ما مجبوریم پلی مورفیسم کنیم. پس اگر خودمان کلاس والد را بنویسیم که حواسمان است و اما گاهی اوقات کلاس والد از قبل نوشته شده است و ما صرفا از آن استفاده می کنیم. پیشفرض نوشته شده و ما استفاده می کنیم و آنها را override می کنیم.
اما متد print در کلاسhuman شامل یک خط است و این خط در کلاس student مجددا پیاده سازی شده ، الان که متد print یک خطی است خیلی فرق نمی کند اما اگر فرض کنید که متد print در کلاس human 100 خط بود و ما می خواستیم فقط یک خط به آن اضافه کنیم ، اینجا پلی مورفیسم کار را خراب می کند. به همین خاطر ما از وراثت استفاده می کنیم به این صورت که:
می دانیم name و family را کلاسhuman چاپ می کند و کلاس student می تواند ایندو را از human بگیرد و فقط number را اضافه تر چاپ کند. پس ما ابتدا print کلاس human را فراخوانی می کنیم و بعد فقط number را چاپ می کنیم. در اینجا هنوز وراثت پابرجا است یعنی ما پلی مورفیسم کردیم و کد ها را تکمیل کردیم.
پلی مورفیسم به این اشاره می کند که متدی از کلاس والد کامل و یا کارا نباشد. اگر کارا نباشد که مجبوریم کل کد ها را بنویسیم اما اگرکامل نباشد مثل مثال قبل، صرفا آن چند خط را اضافه می کنیم .
اکنون به ادامه ی مثال قبلی بر می گردیم.
برای اینکه به آن بفهمانیم که این print مال human است از کلمه ی کلیدی super استفاده می کنیم. این کلمه کلیدی به کلاس والد و اعضای آن اشاره می کند، همانطور که کلمه کلیدی this به خود کلاس و اعضایش اشاره می کند.
استفاده از super
هرگاه لازم باشد تا یک زیر کلاس به کلاس بالای قبلی خودش ارجاع نماید ، اینکار را با واژه ی کلیدی super انجام می دهیم. که دو شکل عمومی دارد. اولین آن سازنده کلاس بالا را فراخوانی می کند. دومین آن به منظور دسترسی به یک عضو کلاس بالا که توسط یک عضو زیر کلاس مخفی مانده است، استفاده می شود. در آینده در مورد این مفصل توضیح خواهم داد.واژه کلیدی this
گاهی اوقات لازم است یک متد به شی ای که آن را فراخوانی نموده ، ارجاع نماید. This را می توان داخل هر متدی برای ارجاع به شی جاری (current) استفاده نمود. می توانید از this هر جایی که ارجاع به یک شی از نوع کلاس جاری مجاز باشد، استفاده نمایید. در آینده در مورد این مفصل توضیح خواهم داد.استفاده از مطالب این مقاله با ذکر منبع راسخون بلامانع می باشد.
ادامه دارد...
/ج