مطالبي كه در اين قسمت خواهيد ديد :
شيء چيست؟
ارثبري يا Inheritance
انتزاع يا Abstraction
كپسولهكردن يا Encapsulation
چندريختي يا Polymorphism
يکی از مهمترين و اصلی ترين مشکلات برای افرادی که به تازگی با محيطهای برنامه نويسی شیگرا آشنا می شوند، درک مفاهيم شيءگرائي است. در حقيقت درک مفاهيمي چون شیء و مولفه (Component) بسيار دشوار نيست، کافيست کمي به اطراف خود با دقت نگاه کنيم. ما در دنيايي از اشياء مختلف زندگی ميکنيم. تلويزيون، راديو در و پنجره، همه و همه نمونه هايی از اشياء مختلفي هستند که در اطراف ما وجود دارند. اما درک و پيادهسازی اين مفهوم در يک زبان برنامهسازی اندکی متفاوت است.
شیء چيست؟
همانطور که گفتيم، با يک ديد تصويری به سادگی می توانيد اشياء مختلفی را در اطراف خود بيابيد. تمامی اين اشياء دارای سطوح و درجه پيچيدگی متفاوتی هستند. پيچيدگی آنها به شکل ظاهری و نوع رفتار آنها بستگی دارد.
در شیء گرايی به "شکل ظاهر" در اصطلاح، صفت يا Attribute و به عملی که شیء انجام می دهد، رفتار يا Behavior می گويند.
برای مثال يک صندلی را در نظر بگيريد. صندلی صفات مختلفی دارد ولی رفتار خاصی ندارد. مثلاً پايه های صندلی جزو صفات آن بشمار می روند. با کمی دقيق تر شدن می توان از اين صفات برای توصيف صندلی استفاده کرد. بعنوان مثال تعداد پايه های صندلی می تواند عددی بين 3 تا 5 باشد. محل نشستن صندلی می تواند جملهاي در وصف جنس آن و مقدار مصرف ماده سازنده آن باشد. پشتی صندلی را نيز می توان بعنوان متغييری boolean در نظر گرفت چراکه برخی از صندلی ها فاقد پشتی هستند. با استفاده از اين سه صفت ساده، به راحتی می توان صندلی را توصيف نمود و با همين سه صفت ميتوان گونههای مختلفی از صندلی را نيز توصيف کرد.
منظور از رفتار، عملی است که يک شیء انجام می دهد. از اينرو برای صندلی نمی توان به سادگی صفات آن، رفتاری را متصور شد. مثلاً ميتوانيم بگوئيم تاشو بودن صندلی يکی از رفتارهای آن می تواند باشد، چراکه عملی است كه می تواند يک صندلی آنرا انجام دهد.
حال شیء ديگری مانند تلويزيون را در نظر بگيريد. صفاتی که می توان برای تلويزيون در نظر گرفت عبارتند از : صفحه نمايش، سازنده آن و ... برای تلويزيون به راحتی می توان رفتار در نظر گرفت : خاموش و روشن شدن، تغيير کانال و کم و زياد کردن صدا. اين رفتارها بر اثر درخواست يک انسان يا همان کاربر اتفاق می افتند.
بطور کلی، يک شیء را ميتوان بوسيله صفات و رفتارهای آن بطور کامل توصيف نمود. يک شیء حتماً جسمی فيزيکی نيست، بلکه هر چيز قابل تصوری است که دارای صفت و رفتار است. در حقيقت ميتوان گفت يک شیء شبيه به يک اسم است. اگر بتوان برای اين اسم، صفت و رفتاری تعريف کرد، آن وقت تبديل به شیء می شود.
از ديد انتزاعی، زمان را نيز می توان بعنوان يک شیء در نظر گرفت. صفات زمان، ساعت، دقيقه و ثانيه هستند و گذشت زمان، رفتار آن است. در ايجاد شیء هيچ محدوديتی وجود ندارد و همه چيز به تخيل شما باز ميگردد.
در زبان C#، اشياء بوسيله کلاسها (Class) نمايش داده می شوند. داخل کلاس، صفات بصورت فيلدها ظاهر می شوند و جهت پياده سازی رفتارها از متدها استفاده می گردد. به مثال زير توجه نمايد :
كد: |
class Time |
در اين مثال، کلاس Time مشاهده می شود. اين کلاس با کلمه کليدی class اعلان گرديده است. همانطور که ميدانيد، دو کروشه باز و بسته {} نيز ابتدا و انتهای کلاس را مشخص ميکند. فيلدها دارای نام و نوع هستند. متدها دارای نام و نوع بازگشتی می باشند و پيادهسازی آنها داخل بلوک مربوط به خود آنها (بين دو {}) انجام ميگردد.
يک شیء ميتواند هر يک از نيازمنديهای يک پروژه باشد. طراحی و اعلان صحيح اشياء و مشخص كردن صفات و رفتار آنها يکی از مقولههای مهم در مهندسی نرم افزار بر پايه شیءگرائي است، چراکه همگی تراکنشها بين اشياء صورت می پذيرند.
کلاسه کردن اشياء (مقدمه ای بر ارث بری Inheritance)
طبقهبندی اشياء در گروههای مختلف بسيار سودمند است. زمين شناسان سنگها را طبقه بندی ميکنند و زيست شناسان گياهان و حيوانات را طبقهبندی ميکنند. طبقه بندی اشياء باعث ميشود تا با دقت و ظرافت بيشتری بتوان به جزئيات هر طبقه و يا هر نوع پرداخت.
برای مثال حيوانات را در نظر بگيريد. زيست شناسان حيوانات را به دستههای پرندگان، مهره داران و خزندگان تقسيم ميکنند. پرندگان صفاتی همچون منقار و بال دارند، مهرهداران بدنی مودار دارند و خون گرمند و خزندگان خون سردند. از ديد رفتاری نيز پرندگان پرواز می کنند، مهره داران به بچه های خود شير ميدهند و خزندگان ميخزند. اينها ويژگيهای ارشد يا عام هستند و صفات ديگری در زير گروهها افزوده ميشوند. در گروه اصلی تنها صفات و رفتارهايی قرار ميگيرند که عموميت داشته باشند و ساير صفات و رفتارها در زير گروهها معين ميگردند. بعنوان مثال کلاس پرندگان را بشکل زير ميتوان پيادهسازی نمود :
كد: |
class Bird |
می توان اين کلاس را بعنوان کلاسی عمومی برای پرندگان در نظر گرفت که دارای فيلدی جهت تعيين نوع پرنده نيز ميباشد. با استفاده از فيلد typeOfBird ميتوان گونه پرنده مورد نظر را معين نمود.
سلسله مراتب اشياء (بررسی ارث بری در محيط شیءگرا)
روش گفته شده در بالا، جهت افزودن صفات برای يک طبقهبندی ساده کارآمد است، اما برای طبقهبنديهای پيچيده قابل قبول نيست. تصور کنيد حجم عظيمی نيازمندی در پروژه وجود داشته باشد و به سطح های مختلفی از طبقه بندی نياز داشته باشيد. با افزودن صفات جديد به هر يک از طبقات و سطحها به پيچيدگی پروژه به شدت افزوده می شود.
اتفاقی که در مورد زير شاخهها رخ ميدهد، ايجاد يک سلسله مراتب طبيعی است. برنامهنويسی شیءگرا ، متدولوژيی را جهت مديريت سلسله مراتب طبيعی فراهم می نمايد. بعنوان مثال، اگر در يک پروژه يکی از طبقه بنديهای ما حيوانات باشند، منطقی است که شیءاي از طبقه حيوانات در رأس سلسله مراتب قرار گيرد و در طبقات و زير شاخههای سطوح پائينی، پرندگان، مهره داران و خزندگان قرار گيرند. در سطح بعدی ميتوان چند پرنده مانند اردک، کلاغ و ... را نيز در زير شاخه پرندگان قرار داد. اين سلسله مراتب تا سطح مورد نظر قابل تعميم است.
در برنامه نويسی شیءگرا، مفهومی که اشياء را تحت يک سلسله مراتب خاص قرار ميدهد، ارثبری يا Inheritance ناميده ميشود. مثلاً طبقهبندی حيوانات را در نظر بگيريد، شیءای که در بالاترين سطح قرار ميگيرد، شیء Animal است. اين شیء دارای ويژگيهايی بسيار کلی و عمومی است و بايد چنين هم باشد، چراکه سرگروه بايد هميشه ويژگيهايی را داشته باشد که در زير شاخه ها بطور مشترک وجود دارد و هر يک از زير شاخهها به ويژگيهای سرگروه خود، ويژگيها و مشخصات خاص خود را می افزايند.
در اين مثال، سرگروه Animal تنها ميتواند دارای صفت يگانه "زيستن" باشد، چراکه همين صفت آنرا از ساير اشياء، نظير سنگ و در و پنجره و بطور کل اجسام، متمايز مینمايد. رفتار اين شیء نيز می تواند "تنفس کردن" و "غذا خوردن" باشد. حال برای اينکه شیءای بتواند در اين سلسله مراتب وارد شود، حداقل بايد دارای صفت شیء سرگروه اين سلسله مراتب باشد، درغير اينصورت نميتواند در زير شاخه آن قرار گيرد.
تفاوت Animal با ساير اشياء که در اين سلسله مراتب قرار ميگيرند در آنست که ساير اشياء ميبايست صفاتی ديگر و - يا رفتارهای ديگری را نيز به صفات و رفتارهای Animal اضافه کنند. اين صفات و رفتارها مسلماً جزئیتر و دقيقتر از صفات و رفتارهای سرگروه است. همين مسئله مفهومی را در پيمايش سلسله مراتبها بوجود میآورد : در پيمايش بالا به پائين (Top-Down) سلسله مراتبها به جزئيات يا گونههای خاص برخورد ميکنيم، حال آنکه در پيمايش پائين با بالا (Bottom-Up) به گروهها و دستههای عمومی ميرسيم.
اشياء سطوح پائينی (که به آنها child ميگوئيم) صفات و رفتارهای اشياء سطح بالاتر خود را به ارث ميبرند. به اين اشياء بالاتر يا سرگروهها نيز parent ميگوئيم. به اين رابطه موجود بين child و parent در اصطلاح رابطه "هست" يا "بودن" (is-a relationship) ميگويند. مثلاً ميگوئيم "اردک يک پرنده است".
سادگی ارث بری از نحوه ايجاد سلسله مراتب ارثبری نشأط ميگيرد. اشياء سطوح پائينی (child) در تعريف خود اشياء سطوح بالايی (parent) خود را مشخص ميکنند. در اين جا تنها کاری که لازم است يک child نسبت به parent خود انجام دهد افزودن صفات و رفتارهای مربوط به خود است.
علاوه بر طبقهبندی اشیاء در دستههای مختلف و سادگی در سازماندهی آنها بوسيله ارثبری، استفاده از ارثبری در انجام کارها نيز صرفهجويی ايجاد ميکند. هر شیء جديدی که به يک سلسله مراتب وارد ميشود، بطور خودکار تمامی صفات و رفتارهای کليه parent های خود را دارا ميباشد و بعلت ارثبری نيازی به تعريف مجدد اين صفات برای شیء جديد نمیباشد. به بيان ديگر ميتوان گفت، ارثبری روشی برای استفاده مجدد از صفات و رفتارهای موجود است.
استفاده از ارثبری اين امکان را برای طراحان نرم افزار فراهم ميکند تا وقت بيشتری برای تفکر بر روی منطق برنامه صرف کنند و درگير پيچيدگيهای پيادهسازی و نگهداری نرم افزار نشوند.
انتزاع (Abstraction)
اکنون زمان مناسبی برای بحث درباره انتزاع است. برخی اشياء تا حدودی انتزاعی هستند و برخی ديگر کاملاً واقعی. بعنوان مثال، چيزی بعنوان Animal وجود ندارد، بلکه اين تنها توصيف کلاسی از اشياء است. همچنين موجوديتی وجود ندارد که از لحاظ فيزيکی يک پرنده باشد. اين تنها طبقهبندی و دستهبندی است که مورد استفاده قرار ميگيرد.
از طرف ديگر شیءای وجود دارد بنام اردک که واقعاً يک اردک است و دارای کليه صفات و رفتارهای آن ميباشد. البته بايد توجه داشت که هر اردک تنها نمونهای از "اردک" است. (منظور در اينجا آنست که موجوديتی مانند يک اردک که واقعا وجود دارد، خود نمونهای (instance) از کلاس اردک است. درک مطالب در اينجا شايد به اندکی تأمل و حوصله نياز داشته باشد!)
برای شیءای مانند Animal يا Bird، نمیتوان صفتی همچون "پاهايی پهن" و يا رفتاری مانند "را رفتن شبيه به اردک" را تعريف نمود. همچنين از اشياء Animal و Bird تنها يک نمونه ميتواند وجود داشته باشد که اين نمونهها نيز بسيار مهم هستند، چراکه اين نمونهها هستند که ساختار يک سلسله مراتب را تشکيل ميدهند و صفات و رفتارهای کلی آن را معين مينمايند. ( البته توجه کنيد که استفاده از کلمه abstract در زبان C# خود يگانه بودن و همچنين انتزاعی بودن کلاس را نشان ميدهد.)
تعريف و توصيف صحيح اين اشياء انتزاعی، همچون Animal و Bird، در طبقهبندی و کارآمدی ساختار سلسله مراتبی بسيار میتواند موثر باشد. مثال زير نحوه تعريف و ايجاد اشياء انتزاعی در C# را نشان می دهد.
كد: |
abstract class Animal |
در اين مثال کلاس Animal بصورت abstract اعلان شده تا مشخص شود که شیءای انتزاعی است. چون شیء انتزاعی عملاً وجود ندارد، نمیتوان نمونهای جديد از روی آن ايجاد کرد و تنها يک شیء از آن وجود دارد. در کلاس دوم، Bird، نشان داده شده است که اين کلاس از کلاس انتزاعی Animal ارثبری دارد. اين عمل با استفاده از ":" در جلوی نام Bird و سپس به دنبال آن نام کلاسی که Bird از آن ارثبری ميکند، يعنی همان Animal، صورت گرفته است.
اشياء درون اشياء (مقدمه ای بر کپسولهکردن يا Encapsulation)
ساختارهای سلسله مراتبی روشی جهت دستيابی به روابط بين اشياء هستند. هر چند روشهای ديگری نيز برای نشان دادن روابط بين اشياء وجود دارد. يکی از اين روشها که بسيار معمول نيز هست، استفاده از اشياء درون اشيائی ديگر است.
يکی از اصطلاحات رايج برای بيان اين مفهوم، کپسولهکردن يا Encapsulation است. استفاده صحيح از اين مفهوم باعث کاهش پيچيدگی شده و تنها آن قسمت اطلاعات و جزئيات را نمايان ميکند که برای درک يک شیء لازم است. بعنوان مثال، پرواز پرندگان مسئلهای است که توجه بسياری از زيست شناسان را به خود جلب کرده است. آنها برای درک پرواز، ساختار بالها، پرها و اسکلت پرندگان را مورد مطالعه قرار میدهند. برای درک پرواز، بررسی همين اجزاء و جزئيات کافيست و نيازی به مطالعه درباره سيستم گوارش پرندگان نمیباشد. برای بررسی يك موضوع تنها اطلاعاتی مربوط به آن در حل و بررسی مسئله میتواند موثر باشد و اطلاعات اضافی، نه تنها وقتگير و بی فايده است، بلکه میتواند گيج کننده نيز باشد و بر پيچيدگی مسئله ، بدون دليل، بيفزايد. با استفاده از کپسولهکردن تنها آن قسمت از اطلاعات که مورد نظر است در دسترس قرار ميگيرند.
شیء Bird را که قبلاً درباره آن صحبت کرديم، در نظر بگيريد. پرندگان دارای منقار و بال هستند. خود بال يک شیء است که دارای صفاتی نظير پر و اندازه است. رفتار آن نيز میتوان باز و بسته شدن در حين پرواز باشد. نکته قابل اشاره در اينجا، کلمه "داشتن" است. اعمالی وجود دارند که پرنده آنها را انجام ميدهد و اين اعمال خود جزئی از پرنده هستند.
بطور کلی، رابطه "داشتن" (has-a relationship) بين يک شیء و اعمالی که بر روی اجزای خود انجام ميدهد، وجود دارد. بعنوان مثال ميگوئيم "پرنده بال دارد". در اينجا چون بال شیءای متعلق به پرنده است که پرنده روی آن عملی انجام ميدهد، مفهوم کپسولهکردن رخ ميدهد، شیءای درون شیءای ديگر. مثال زير نحوه پيادهسازی کپسولهکردن را نشان ميدهد.
كد: |
class Wing |
در اين مثال، دو کلاس Bird و Wing وجود دارند. کلاس Wing فيلدها و متدهای مربوط به خود را دارد. درون کلاس Bird اعلانی از کلاس Wing با استفاده از نام wings صورت گرفته است. اين عمل رابطه مالکيتی بين Bird و Wing ايجاد مينمايد. "پرنده دارای بال است". تنها چيزی که کافيست بدانيم آنست که کلاس انتزاعی پرنده دارای بال است. توجه کنيد که صفات و رفتارهای کلاس Wing بوسيله خود اين کلاس کنترل ميشوند.
اشيائی با رفتارهايی متفاوت (مقدمه ای بر چندريختی يا Polymorphism)
در برخی شرايط ممکن است نياز داشته باشيم تا علاوه بر اينکه شیءای را در رده خاصی طبقهبندی میکنيم، به آن شیء اين اجازه را نيز بدهيم تا بتواند رفتارهای خاص به خود را داشته باشد.
برای مثال، اردک و يا عقاب اشيايی هستند که با گروه Bird ارتباط دارند. تصور کنيد زيستشناسی ميخواهد رفتارهای اين پرندگان را بررسی نمايد. برای بررسی اين پرندگان لازم است تا زيست شناس آنها را در جايی نگهداری کرده و بر روی آنها مطالعه انجام دهد. مسلماً اين پرندگان بايد در قفس نگهداری شوند اما مطمئناً قفس اردک با قفس عقاب يکسان نمیتواند باشد. اين بدين معناست، قفسی را که تعريف ميکنيم بايد طوری باشد تا برای اکثر گونههای پرندگان مناسب باشد. ميتوانيم قفسی مخصوص پرندگانی که پرواز ميکنند در نظر بگيريم. از اينرو پرندگانی را که پرواز ميکنند را در اين قفس قرار ميدهيم. همانطور که مشاهده ميکنيد، دستهبندی پرندگان در يک گروه جهت رسيدن به اهداف پروژه ضروری است. پيادهسازی مطلب گفته شده بشکل زير است .
كد: |
abstract class flyingBird : Bird |
در کد فوق، 3 کلاس جديد ايجاد شده است. اولين کلاس، flyingBird است که از کلاس Bird مشتق شده است. از آنجائيکه تمامی پرندگان پرواز نمیکنند، اين کلاس ميتواند تنها مخصوص آن دسته از پرندگانی باشد که ميتوانند پرواز نمايند. کلاسهای Eagle و Duck در اين کد از FlyingBird مشتق شدهاند. آخرين کلاس نيز Experiment است که متد Main() در آن قرار گرفته است. درون متد Main()، آرايهای بنام flyingBirdCage از نوع FlyingBird تعريف شده که اين آرايه، مخصوص اشيايی از نوع FlyingBird است. از آنجائيکه کلاسهای Duck و Eagle از نوع FlyingBird هستند، پس ميتوان آنها را در اين آرايه قرار داد. نکته مهم در اينجا نيز همين مطلب است که از اين پس ما پرندگانی داريم که پرواز ميکنند و در قفس مخصوص نگهداری میشوند. حال تصور کنيد که اين نوع قفس وجود نداشت و مجبور بوديم تا برای هر پرنده نوع خاصی از قفس را تعريف نمائيم. در اين شرايط حجم کار بسيار زياد ميشد و به مشکل بر میخورديم. اما هم اکنون میدانيم که قفسی داريم که شرايط کلی و عمومی برای نگهداری پرندگانی که پرواز میکنند را داراست. در صورتيکه برای هر پرنده بخواهيد قفسی مخصوص ايجاد کنيد، کدی شبيه به کد زير مورد نياز بود :
كد: |
class Experiment |
علاوه بر اين تصور کنيد که بخواهيم مشخصات ديگری نيز به کلاسها بيفزائيم. در اين شرايط کار با کدام گزينه سادهتر است؟ کار با آرايهای از اشياء يکسان، يا کار با اشيايی متفاوت؟ مسلماً کار با آرايهها سادهتر است چرا که با استفاده از تنها يک دستور foreach ميتوان کليه عناصر يک آرايه را پيمايش کرد.
پس از ايجاد کلاسهای مربوطه، نوبت به بررسی نحوه پرواز هر پرنده میرسد. اگر کليه پرندگان مورد مطالعه را از نوع پرندگانی که پرواز میکنند در نظر بگيريم و آنها را در قفس مخصوص اين پرندگان قرار دهيم، مسئله بعدی نحوه پرواز هر يک از اين پرندگان است.
عمل پرواز کردن، در کليه اين پرندگان وجود دارد، ولی نحوه پرواز در هر يک از آنها مسلماً متفاوت است. اين مفهوم دقيقاً با مفهوم چندريختی (Polymorphism) در شیءگرايی مطابقت دارد. Polymorphism توانايی انجام يک عمل توسط اشياء مختلف است که به شکلهای مختلف انجام می گيرد. مثال زير نحوه پيادهسازی Polymorphism در زبان C# را نشان میدهد.
كد: |
using System; |
خروجی اين برنامه بشکل زير است :
كد: |
Eagel Fly |
در اين مثال، کلاسهای Eagel و Duck از کلاس FlyingBird مشتق شدهاند. هر يک از اين کلاسها دارای متد Fly() هستند. تنها تفاوت اين متدها در نحوه اعلان و پيادهسازی آنهاست. در کلاس FlyingBird، متد Fly() بصورت virtual اعلان شده است، بدين معنا که کلاسهای مشتق شده از اين کلاس میتوانند شخصاً به پيادهسازی اين متد بپردازند. پيادهسازی اين متد در کلاسهای مشتق شده با استفاده از کلمه کليد override صورت میگيرد. در متد Main() با استفاده از يک حلقه foreach، تک تک اين متدها فراخوانی میشوند. بعلت اينکه کليه اين متدها بصورت override تعريف شدهاند، در فراخوانی بصورت مجزا اجرا میشوند.
به همين ويژگی، يعنی داشتن يک رفتار در گروهی از اشياء که هر يک از آنها اين رفتار را بصورت دلخواه خود پيادهسازی میکنند، Polymorphism گفته ميشود. استفاده از Polymorphism در حل مسايل پيچيده بسيار سودمند است.
مریم
با تشکر فراوان
مطالب خیلی مفید هستند
امیدوارم به همین صورت ادامه پیدا کنند
من علی هستم
آدرس وبلاگم www.csvb.tk
متشکرم، مطلاب خوب و بدرد بخوری در وبلاگ شما وجود داره، امیدوارم تو کارت موفق بشی
اگه دوست داشتی میتونیم با هم تبادل لینک کنیم
یک کتاب جدید هم توسط خانم بیات نوشته شده که خواهش می کنم در صورت تمایل در وبلاگتون قرار بدبد
آدرس