فصل 6_بخش هشتم:انواع کلاس داخلی(inner and instade)و کلاس ناشناخته  

از آنجا که class وobject مربوط به مدل سازی از دنیای بیرون است بیایید برای توضیح مطلب بالا از مثال مدل سازی اتم شروع کنیم :

به عنوان مثال اتم به عنوان نام کلاس اصلی (outer) در نظر می گیریم و الکترون و پروتون و نوترون را به صورت کلاس instead (کلاس داخلی تر) در نظر می گیریم
که هرکدام از این کلاس ها زیر مجموعه کلاس insted جداگانه دارند (ذرات زیر اتمی) حالا هرگاه فقط در اطلاعاتی که می خواهیم استخراج کنیم به وسیله object که در فایل main بود. و می خواهیم تنها اطلاعات پروتون را مشاهده کنیم و این اطلاعات را می خواهیم به صورت مستقل ارائه دهیم
نباید از کلید واژه inner. قبل از لغت class مربوط به الکترون استفاده کنیم.
و اگر اطلاعات اتم را نیز می خواهیم استخراج کنیم و مرتبط اش کنیم به اطلاعات کلاس درونی مثلا پروتون بایستی کلید واژه inner را قبل از آن بیا وریم.
کار کلید واژه inner به طور خلاصه :
کلاس بالا دستی که در آن قرار دارد را مجبور می کند از آن آبجکت ساخته شود بدین ترتیب می توانیم هم به متد ها و آبجکت های کلاس بیرونی دسترسی داشته باشیم و هم به آبجکت ها و کلاس های درونی.
و اگر از آن استفاده نشود می توان بدون ساخت کانستراکتور از کلاس بیرونی به کلاس درونی یعنی متد ها وinjection هایش دسترسی داشته باشیم و برای این منظور آن را کانستراکتور دار می کنیم.

مطلب بعدی :کلاس ناشناخته(anonymous class) :
هنگامی که می خواهیم از یک اینترفیس ارث بری کنیم توسط یک object می بایست ابتدا مثل کلاس از آن ارث بری کنیم سپس کلید واژه object را می نویسیم سپس دوباره از آن اینترفیس ارث بری می کنیم سپس آکولاد باز و بسته را می گذاریم و تمامی
فیلد ها و متد ها را مقدار دهی می کنیم.
سپس هر فیلد و متدی که خواستیم صدا می زنیم.

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

>
شکل1:class.kt

>
شکل2:interface.kt

>
شکل3:file.kt

>
شکل4: کنسول Intelij Idea

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

فصل6_ بخش هفتم:یادگیری بیشتر در مورد[ انتزاع](Interface and Abstract classes)

همانطور که قبلا گفته شد مفهوم abstract همان black box است که بدین معنا است که هرچه درصد abstract ما از محیط اطراف بیشتر باشد نشان دهنده دانش کمتر ما نسبت به آن هاست و ما صرفا استفاده کننده یا نگهدارنده آن ها هستیم .

وقتی پشت یک class کلید واژه abstract استفاده می کنیم یعنی ما آن کلاس را می توانیم بین 0 تا 100 درصد به آن مفهوم black box دهیم .یعنی با استفاده از آوردن کلید واژه abstract پشت تعریف method ها و انواع injection هایمان می توانیم مقدار دهی یا بدنه method ها را به کلاس های فرزند الحاق کنیم یا خودمان مستقیما پیاده سازی را انجام دهیم(بدون آوردن کلید واژه abstract) و اگر در فرزندی پیاده سازی متفاوت بود قبل از ان کلید واژه open به کار ببریم .

در واقع فرق کلید واژه abstract قبل از متد ها و injection ها با کلید واژه open در این نوع کلاس ها (Abstract classes)در این است که کلید واژه اولی override کردن را برای کلاس های فرزند اجباری می کند و در صورت عدم override با خطای کامپایلری مواجه می شویم اما کلید واژه دومی (open)از polymorphismهای اختیاری است که از نوع overrideاست در فرزندان .

بدین ترتیب در abstract class ها می توانیم بدون هیچ پیاده سازی black box 100% یا با درصدی پیاده سازی black box 100% .. 0% داشته باشیم .

نکته: abstract class ها و class های عادی دو نوع ارث بری را می توانند داشته باشند :

1_ ارث بری تکی یعنی فقط به یک class ساده دیگر ارث بری کنند .(البته abstract class می تواند از نوع خودش هم ارث بری تکی داشته باشد )

2_ارث بری چند مرحله ای یعنی کلاس ها از هم به ترتیب از بالا به پایین ارث بری کنند .

نکته :قابل توجه است که از یک کلاس یا Abstractکلاس می توان چند کلاس یا Abstractکلاس ارث بری کنند .(به بیان ساده یک والد می تواند (چند فرزند داشته باشد )

نکته :ارث بری از بیش از یک والد بدون استفاده از intreface ها غیر ممکن است.

Interface ها این امکان را برایمان فراهم می کنند تا دید black box 100% را داشته باشیم .

اما در زبان کاتلین این امکان فراهم شده تا یک پیاده سازی جزیی هم در interface ها داشته باشیم (در صورت دلخواه).

نکته:interface ها فاقد سازنده یا همان constructor هستند .بنابراین هنگام ارث بری نباید پرانتز باز و بسته بعد از اسم interface بگذاریم .

نکته :تمامی فانکشن ها و فیلد injection های مربوط به intreface ها به طور پیش فرض abstract هستند و نیازی به گذاشتن این کلید واژه نیست .

نکته : هنگامی که چند interface و یک abstract کلاس می سازیم می توانیم سه راهکار داشته باشیم یا همه را به یک abstract class کلاس ارث بری کنیم که اجباری به override نمودن متد ها و فیلد هایمان که abstract بودند نداریم .ولی درصورت دلخواه می توانیم این کار را انجام دهیم .

یا همه را به یک interface ارث بری می کنیم که در این صورت به طور معمول اصلا نمی خواهیم override انجام دهیم .

یا همه را به یک کلاس معمولی ارث بری می کنیم که در این صورت با نگه داشتن control و Alt و زدن دکمه Enter یک صفحه برایمان باز می شود که لیست متد ها و فیلد injection ها را برایمان می اورد و با نگه داشتن دکمه control و A باعث می شود کل ان ها انتخاب شود و بازدن دکمه Enter کل متد ها و injection ها به طور پیش فرض تعریف می شوند و فقط کافی است مقادیر را در injection ها جایگزین و بدنه متد هایمان را بنویسیم .

حالا از شما می خواهم طبق توضیحات زیر و با توجه به مطالبی که تا حالا در فصل 6 خواندیم یعنی(classها وfieldها و encapsulationها و abstract ها وinheritance ها و polymorphism ها ) ابتدا مثالی که برای شما با جز ییات کامل می زنم را در زبان کاتلین پیاده سازی کنید سپس خروجی تان را با خروجی من یعنی همان شکل مربوط به کنسول Intelij Idea مقایسه کنید و در صورت داشتن ایراد به سایر شکل ها توجه کنید.

کارخانه تولید ماشین مادر بسازید به طوریکه این کارخانه قادر است سه مدل ماشین Volvo و Benz و BMW را تولید کند .

این کارخانه از اجزای کوچگ تری ساخته شده است که به طور ناچار بایستی از آن ها ارث بری کند :(کارخانه فرزند قسمت های زیر هست )

1_ قسمت گیر بکس ساز که دو نوع گیر بکس اتو ماتیک و گیربکس دستی از ان ارث می برند .

2 _ قسمت ساخت تایر که دو نوع تایر اسپرت (پهن)و تایر معمولی از ان ارث می برند .

3_ قسمت ساخت شیشه ماشین که سه نوع شیشه ضد گلوله و شیشه دودی و شیشه معمولی از ان ارث می برند .

4_ قسمت ساخت موتور که دو نوع 6 سیلندر و 4 سیلندر از ان ارث می برند

5_قسمت ساخت ترمز که دو نوع ترمز معمولی و ترمز abs از ان ارث می برد

برای استفاده از کانستراکتور که در نکته 1 آمده بایستی زیر مجموعه های ساخت هر قسمت را به صورت کانستراکتوری طبقه بندی کنید .

یا برخی را کانستراکتوری کنید و برخی را به صورت overload بنویسید .

سپس هرکدام از محصولات ارث بری کنند از کارخانه مادر .

و در انتها با شماره مدل object هایی از ماشین های Volvo و Benz و BMW بسازید در فایل main.kt و رفتار ها و فیلد ها را صدا بزنید .

نکته1 : با استفاده از ارث بری انتخابی از هرکدام از زیر مجموعه های کارخانه مادر یا با استفاده از کانستراکتور ها ویژگی خاص هر ماشین را شبیه سازی کنید .

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

تذکر:مدلی که در زیر نوشته شده تقریبا با توضیحات بالا تطابق دارد.

به 8 شکل زیر با دقت توجه کنید:

>
شکل1:Intrface.kt

>
شکل2:Intrface.kt

>
شکل3:Intrface.kt

>
شکل4:Intrface.kt

>
شکل5:Intrface.kt

>
شکل6 قسمت1:class.kt

>
شکل6 قسمت2:class.kt

>
شکل7:file.kt

>
شکل8: کنسول Intelij Idea

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

فصل 6_ بخش ششم:ارث بری و چند ریختی ها (inheritance And polymorphisms)

Inheritance[ ارث بری ] :

در ارث بری به کلاس بالا دستی (کلاس پدر )کلید واژه (super)به کاربرده می شود و به فرزندان به اصطلاح (sub class) می گویند .

کاربرد ارث بری : هنگامی که می خواهیم یک کلاس تمام ویژگی ها و متد هایش به کلاس دیگر انتقال یابد می بایست کلید واژه open را قبل از تعریف کلاس اول

(کلاس پدر) بیاوریم و سپس جلوی کلاس فرزند علامت ' : ' را بیاوریم سپس اسم کلاس پدر رابیاوریم و سپس در ساده ترین حالت ممکن یک پرانتز باز و بسته بیاوریم . سپس بدنه کلاس فرزند را ایجاد کنیم .

اگر یک یا چند تا از subکلاس ها ویژگی دارند که با سایرین متفاوت است و این ویژگی متفاوت جز injection ها (خصوصیات )یا متد های کلاس پدر است می بایست یکی از این دو راه را طبق دانش فعلی خود انتخاب کنیم .

1_ یا به طور کلی این چند sub کلاس ها ویژگی متفاوت شان در خودشان پیاده سازی شود . و سایر sub کلاس ها فاقد آن شوند و چون از همان اول در متد پدر وجود نداشته .

2_ یا به طور کلی اگر تفاوت زیاد شد (( به خاطر رعایت کردن قانون [D.R.Y](Do'nt Repeed Yourself)که باعث می شود خطای برنامه نویسی کم شود )) از super کلاس دیگر ارث بری کنند .

کاربرد اصلی سطح دسترسی ' protecdet' در super کلاس می باشد و باعث می شود بتوانیم بدون اینکه در فایل main.kt آبجکتی (شی ای) بسازیم بتوانیم آن را فقط در کلاس های فرزندان استفاده کنیم .

به شکل های زیر با دقت نگاه کنید(شکل های شماره یک) :

>
شکل1:class.kt

>
شکل2:class.kt

>
شکل3:class.kt

>
شکل4:class.kt

>
شکل5:class.kt

>
شکل6:file.kt

>
شکل7: کنسول Intelij Idea

Polymorphisms[ چند ریختی ها ]:

که به طور کلی به دو نوع است : 1_override و 2_ overload

ابتدا به نحوه پیاده سازی این دو اصطلاح که زیر مجموعه polymorphism ها هستند می پردازیم و سپس 5 تفاوت اصلی بین این دو را برایتان شرح می دهم :

override: در بین دو کلاس فرزند و والد اتفاق می افتد که اگر بخواهیم متد یا injection ای به صورت متفاوت در فرزندان اجرا شود . عین اسم متد با کلمه کلیدی fun قبل اش می اوریمو قبل کلمه fun که مخفف function است کلید واژه override را می اوریم . و قبل از همان متد مربوطه در والد کلید واژه open را می آوریم .(( و باید دقیقا با همان امضای تابع چه از نظر نوع پارامتر های ورودی و تعداد پارامتر های ورودی و چه از نظر نوع بازگشتی آن برابر متد والد باشد و تنها فرق آن که آن را متمایز می کند کد های داخل بدنه آن است .))

برای field injection هم می توانید عینا از val یا var استفاده شده در کلاس والد استفاده کنید و عینا از نام گذاری و نوع دیتا دادهای که در والد استفاده شده و فقط مقدار داده را تغییر دهید و همانند قسمت متد باقی قسمت ها را تکمیل کنید .

overload:در یک کلاس اتفاق می افتد و به این صورت است که چند متد با نام های یکسان ایجاد می کنیم و تنها تفاوت اجباری در آن ها باید نوع و تعداد پارامتر های ورودی باشد که در امضای تابع نوشته می شود . باشد تا حالت overload اتفاق بیفتد .

5 تفاوت اصلی override و overload :

1 _overload برای خوانایی بیشتر کد استفاده می شود ولی

override برای یک پیاده سازی خاص که در متد فرزند و والد وجود داشته می توان استفاده کرد .

2 _ overload داخل یک کلاس اتفاق می افتد ولی

override داخل دو کلاس اتفاق می افتد

3 _ هنگام overload کردن پارامتر ها باید دقیقا با هم متفاوت باشند(در امضای تابع ) ولی

در override کردن امضای تابع دقیقا باید با امضای تابع والد برابری کند .

4_ overload هنگام compile time اتفاق می افتد ولی

override در زمان run time اتفاق می افتد .

5 _ در overloadمقدار بازگشتی را تغییر دهیم هیچ اتفاقی نمی افتد ولی

در override حتی مقدار بازگشتی در امضای تابع مهم است و باید کاملا مطابق متد والد باشد .

به چند شکل زیر با دقت توجه کنید(شکل های شماره 2) :

>
شکل1:class.kt

>
شکل2:class.kt

>
شکل3:class.kt

>
شکل4:class.kt

>
شکل5:class.kt

>
شکل6:file.kt

>
شکل7: کنسول Intelij Idea

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

فصل6 _ بخش پنجم:مفهوم انتزاع و کپسوله سازی (Abstraction  and  Encapsulation)

ابتدا دو مفهوم (black box) و (white box) را بررسی می کنیم :

به طور کلی ما در زندگی نسبت به بیشتر اشیا دید جعبه سیاه داریم : یعنی تنها استفاده از آن ها می کنیم و تخصصی در مورد آن ها نداریم . مثلا یک صندلی , بادکنک , چراغ, لوستر را در نظر بگیرید کم تر کسی بین ما تخصص دارد که بتواند صفر تا صد آن ها را بسازد .

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

ما به این دید black box [جعبه سیاه]Abstraction می گوییم و حتی آن را هم می توانیم به مقدارش درصد صفر یا حتی درصد بین صفر تا صد و صد را اختصاص بدهیم .

بدیهی است که از متخصصین به روز دید Abstraction صفر یعنی همان (white box) صد در صد انتظار می رود .

و به استفاده کننده یک محصول تنها برای مصرف درست از فرآورده یک دید (Abstraction) نزدیک به صد می دهند .

سوالی که اینجا مطرح می شود این است که آیا برای مخفی کردن این اطلاعات از مصرف کننده چیزی در برنامه نویسی تعبیه شده است یا خیر؟

جواب است بلی, تعبیه شده و اصطلاح مربوط به آن کپسوله سازی یا Encapsulation می باشد تا با استفاده از کلید واژه های زیر به بتوانیم سطح مخفی و آشکارا نمودن اطلاعات را تصمیم گیری کنیم .

که این کلید واژه ها عبارتند از :

private:سطح دسترسی به همان فایل یا کلاس یا interface محدود می شود .

protected:سطح دسترسی فقط به فرزندان که از پدر خود ارث برده اند محدود می شوند .

internal:سطح دسترسی فقط به همان ماژولی که برنامه مورد نظر نوشته شده محدود می شود .

public:سطح دسترسی در همه جا ممکن است و به طور کلی به صورت پیش فرض فعال است .

سوال دومی که مطرح می شود این است که در چه مکان هایی اجازه داریم قبل از تعریف آن ها این کلید واژه ها را به کار ببریم؟

1_قبل از Class ها و 2 _ قبل از Objectها 3 _ قبل از interface ها و 4 _ قبل از constructor ها و 5 _ قبل از method ها

6_ قبل از field ها 7_قبل از ()settter و ()getter ها

در ادامه مثال هایی در مورد انواع سطوح دسترسی با آوردن تصاویری از محیط Intelij Idea برایتان می آورم .

به 8 شکل زیر با دقت توجه کنید :

>
شکل1:class.kt

>
شکل2:file.kt

>
شکل3: کنسول Intelij Idea

>
شکل4:class.kt

>
شکل5:class.kt

>
شکل6:class.kt

>
شکل7:file.kt

>
شکل8: کنسول Intelij Idea

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

فصل 6 _ بخش چهارم : setter and getter(تنظیم کننده و دریافت کننده)

در این بخش به setter که می تواند دو متغییر : مقدار جدید (Value)و مقدار قبلی (Field)را بپذیرد تنظیم کننده و به getter که تنها می تواند مقدار قبلی (Field ) را بپذیرد دریافت کننده می گویند .

باید بدانید نوشتن بلوک کد getter ضروری نیست زیرا بیشتر اوقات خود setter کار ما را راه می اندازد . اگر بخواهیم از getter خالی استفاده کنیم نمی توانیم با مقادیر جدید کار کنیم و هر بار object ساخته شده از کلاس که فلید مرتبط را صدا می زند مقدار قدیمی را صدا خواهد کرد و دیگر مقدار جدید یا جدید تر جایی ذخیره نمی شود .

ولی بهترین حالت استفاده از هردو این بلوک کد است و اگر بخواهیم ابتدا شرط یا فعالیتی که در setter موجود هست چک شود که با مقدار جدید نیز سر و کار دارد باید setter را اول بنویسیم ولی اگر می خواهیم ابتدا شرایط و فعالیت های درون getter چک شود که فقط با مقدار قبلی سر و کار دارد بایستی ابتدا بلوک کد getter نوشته شود .

نکته :نوشتن کد هایی مانند کد هایی از جنس کد زیر در setter الزامی است:

اگر مقدار جدید (value)بزرگتر مساوی 1 بود :

چاپ کن: موفقیت

field=value

در غیر اینصورت

چاپ کن :شکست

field= -1000

نکته جنس field و value مورد استفاده در setter و getter از جنس تنها تغییری است که قبل از این یک یا دو بلوک کد آمده است . و برای تعریف متغییر های دیگر در کلاسمان می بایست بعد از این دو بلوک کد درداخل بدنه کلاسمان بیاوریم .

حالا به مثال زیر خوب دقت کنید که شامل موارد زیر است :

کلاس Balance ازکلاس ChangingDollar ارث بری (inheritance) کرده است و اینطور توانسته ایم دلار را در معامله به ریال تبدیل کنیم .

و هنگام ساختن کلاس MyClassهر دفعه هنگام کم کردن مقادیر از data1مقدارش ابتدا نصف می شود و این تقدم اجرا کد (همین که ابتدا نصف می شود سپس از آن مقادیر دلخواه کم می شود ) به خاطر زودتر آوردن بلوک کد getter است .

و مشاهده می کنید در کلاس های نوشته شده تنها کلاس دارای getter همین کلاس MyClass می باشد .

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

>
شکل1:class.kt

>
شکل2:class.kt

>
شکل3:class.kt

>
شکل4:class.kt

>
شکل5:file.kt

>
شکل6: کنسول Intelij Idea

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''