مفاهیم برنامه نویسی شئ گرا

به کمک برنامه‌نویسی شیءگرا می‌توانیم مدل‌سازی نیازهای پیچیده که در دنیای واقعی وجود دارد را بهتر انجام دهیم. در این آموزش مبانی برنامه نویسی شئ گرا را یاد می‌گیریم. ابتدا مفاهیم و اجزا، سپس ۴ اصل آن را با مثال‌های واقعی بررسی می‌کنیم.

برنامه‌نویسی شئ‌گرا (Object Oriented Programming به اختصار OOP) یک شیوه برنامه‌نویسی است که از دنیای واقعی ما الگو گرفته است. اگر به اطراف خود نگاه کنید، همه چیز یک شئ است! به کمک این شیوه، تمام اجرای برنامه را به صورت اشیاء مدل کرده و سپس از آن‌ها استفاده می‌کنیم.

برنامه نویسی شئ گرا چیست ؟

در اولین زبان‌های برنامه‌نویسی تمام برنامه را در کدهای پشتِ سرِ هم می‌نوشتیم. بعد از آن، شیوه‌های رویه‌ای روی کار آمدند که کدها را به قطعه‌های مختلفی که هر کدام عملیات خاصی انجام می‌دهند تقسیم می‌کنیم. سپس هر کجا که نیاز به اجرای آن‌ها داریم، یک تابع برنامه‌نویسی را فراخوانی می‌کنیم.

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

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

در حالت رویه‌ای احتمالاً سه نوع داده تعریف می‌کنیم که کاملاً از یکدیگر جدا هستند. حال اگر بخواهیم تغییر کوچکی در یکی از ویژگی‌های مشترک این‌ها اعمال کنیم، مجبوریم این تغییر را ۳ بار تکرار کنیم!

در ادامه متوجه می‌شوید که پیاده‌سازی و اعمال تغییرات در سیستم (قابلیت نگهداری) با برنامه‌نویسی شیءگرا چقدر آسان‌تر می‌شود.

مفاهیم شیء گرایی

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

  1. کلاس (Class)
  2. شئ (Object)
  3. ویژگی (خصیصه یا Property) که گاهی به آن شناسه (Attribute) گفته می‌شود.
  4. رفتار (Behavior) که به نام که متد (Method) از آن یاد می‌شود.

به زبان خیلی ساده، کلاس یک الگوی (نقشه) کلی برای نوع داده‌ای ما در سیستم است. هر کلاس دارای ویژگی‌ها و رفتارهایی است که برای تمام داده‌های از آن نوع قابل تعریف است. هر گاه از روی این الگو یک داده ساخته و ویژگی‌های آن را تعیین کنیم، یک شئ از آن کلاس در اختیار داریم.

به عملیات ساخت شئ از کلاس، نمونه‌سازی (ساخت instance) گفته می‌شود.

مثال کلاس و اشیاء در OOP
مثال کلاس و اشیاء در OOP

کلاس، متد و ویژگی در برنامه‌نویسی

در مثال سیستم دانشگاه، یک نوع داده‌ای خیلی جامع به اسم «انسان» داریم. مفهوم انسان در دنیای واقعی را تصور کنید. این موجود دارای یک ساختار کلی است که از مجموعه‌ای از ویژگی‌ها و رفتارها ایجاد شده‌اند. برای مثال:

  • سن، رنگ پوست، قد و وزن برخی از ویژگی‌های انسان هستند.
  • راه رفتن، دیدن، خوردن، شنیدن و حرف زدن از رفتارهای اوست. این‌ها رفتارها (متدها) شبیه تابع‌هایی هستند که روی اشیاء از نوع این کلاس قابل اجرا (اصطلاحاً صدا زدن) هستند.

هر گاه مطابق الگوی «انسان» (کلاس) ویژگی‌های خاصی تعریف کنیم، از آن یک شئ ساخته شده است. همه شئ‌های این کلاس، دارای رفتارهای مشابهی هستند اما به دلیل تفاوت در ویژگی‌هایشان تا حد زیادی از یکدیگر متمایز خواهند بود.

آیا می‌توانید یک نوع حیوان (مثلاً گربه) را به صورت کلاس مدل‌سازی کنید؟ سعی کنید این کار را انجام دهید و اگر سؤالی داشتید از قسمت دیدگاه‌های آموزش مطرح کنید.

اصول شیءگرایی به زبان ساده

تا این جا با مفاهیم یا بهتر بگویم، اجزای یک برنامه بر اساس برنامه نویسی شئ گرا آشنا شدیم. مثال‌های بیشتر را در ادامه می‌زنم که این تعاریف را کامل درک کنید.

برنامه‌نویسی شئ‌گرا دارای اصول خاصی است. یعنی علاوه‌بر اینکه باید تمام موجودیت‌های برنامه را بر اساس کلاس‌ها تعریف کنیم، لازم است اصول خاصی را رعایت کنیم.

البته اگر این اصول را رعایت نکنیم یا به درستی از آن‌ها استفاده نکنیم، برنامه ما همچنان یک برنامه شئ‌گرا (Object Oriented) خواهد بود، ولی کیفیت لازم را نخواهد داشت. از این اصول در نوشتن برنامه‌ها بسیار استفاده می‌شود و درک و فهم آن‌ها به شما کمک زیادی خواهد کرد.

تجرید یا انتزاع در برنامه‌نویسی

انتزاع (Abstract) به معنی محدود کردن جزئیات برای پرداختن به فرآیند اصلی است. اجازه دهید با دو مثال از زندگی روزمره شروع کنم:

  • خیلی از ما به عنوان راننده پشت یک ماشین نشسته‌ایم و آن را روشن کرده‌ایم، اما همه از ساز و کارت استارت خوردن و نحوه کار دینام‌ها اطلاعی نداریم.
  • تا به حال با ماکروویو، قهوه ساز یا لباس‌شویی کار کرده‌ایم ولی از ساز و کار آن‌ها اطلاع دقیقی نداریم.

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

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

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

کپسوله‌سازی در برنامه‌نویسی شیءگرا

مطمئناً هر برنامه از اشیاء مختلفی تشکیل شده است. اصل کپسوله‌سازی (Encapsulation) به ما می‌گوید که هر شئ باید از ویژگی‌های خود محافظت کند. یعنی بهتر است اشیاء دیگر به طور مستقیم به ویژگی اشیاء دیگر دسترسی نداشته باشد.

کپسوله سازی یا Encapsulation
کپسوله سازی یا Encapsulation برای اطمینان و امنیت بیشتر

فرض کنید می‌خواهیم یک بازی شطرنج را به صورت شئ‌گرا پیاده‌سازی کنیم. بازی شطرنج از مهره‌هایی تشکیل شدند که هر کدام دارای ویژگی‌ها و رفتارهای مختلفی هستند. یعنی:

  • هر مهره دارای رنگ، شکل، اسم (نوع مهره) و محل قرارگیری خاصی روی صفحه بازی است.
  • هر مهره با توجه به نوعش می‌تواند به شیوه مختلفی روی صفحه بازی حرکت کند.

در یک پیاده‌سازی خیلی ساده، محل مهره را با یک متغیر (ویژگی در کلاس) از نوع عدد مشخص می‌کنیم. همچنین چون همه مهره‌ها دارای رفتارها و ویژگی‌های یکسانی هستند، یک کلاس اصلی برای مهره بازی در نظر می‌گیریم.

شاید بگویید همه مهره‌ها رفتارهای مشابهی ندارند. چون حرکت اسب در صفحه بازی با حرکت رخ بسیار متفاوت است. به کمک ۲ اصل بعدی در برنامه نویسی شئ گرا می‌توانیم این تفاوت‌های جزئی را پیاده‌سازی کنیم.

فعلاً تمرکز ما روی این مسئله هست که همه مهره‌ها دارای ویژگی موقعیت (مثلاً position) و رفتار حرکت کردن به نام move() هستند. اگر بازیکن‌ها (که خودشان یک شئ دیگر هستند) به طور مستقیم به مقدار position دسترسی داشته باشند، نمی‌توانیم هیچ محدودیتی روی نوع حرکت مهره‌ها داشته باشیم.

مثلاً کاربر موقعیت مهره خود را از x به y تغییر می‌دهد. شاید این حرکت طبق قوانین بازی ما مجاز نباشد. پس نباید به بازیکن‌ها اجازه دسترسی مستقیم به موقعیت مهره را بدهیم. در این حالت کاربر متد move() را صدا زده و موقعیت مورد نظرش را اعلام می‌کند، اگر موقعیت خانه مورد نظر طبق قوانین بود، مهره حرکت می‌کند.

کپسوله‌سازی برای ویژگی‌ها، متدها و حتی کلاس‌ها قابل تعریف است.

ارث‌بری کلاس‌ها در OOP

به کمک ارث‌بری (Inheritance) می‌توانیم کلاس‌ها را گسترش داده و ویژگی‌ها و رفتارهای جدیدتری به آن اضافه کنیم. در ۲ مثال زیر یک نمونه خیلی ساده از ارث‌بری در دنیای واقعی را به تصویر کشیدم:

  • همه ماشین‌ها نوعی «خودرو» هستند. همگی در و پنجره داشته و حرکت می‌کنند. اما ماشین‌ها به دسته‌های کوچک‌تری هم تقسیم می‌شوند. مثلاً از نظر سوخت مصرفی می‌توانند متفاوت باشند، که در این صورت عملکرد برخی قسمت‌ها متفاوت خواهد شد. دسته‌بندی دیگر بر اساس امکانات بسیار متفاوت (نظیر سقف بازشو یا دنده اتومات) است.
  • همه جانوران نوعی «حیوان» هستند. آن‌ها راه می‌روند و غذا می‌خورند. در این بین، اسب‌ها با چهار پا راه می‌روند، کرم با خزیدن حرکت می‌کند و ماهی از باله‌های خود کمک می‌گیرند. غذای هر کدام از این‌ها هم متفاوت است.

اگر دقت کنید، همه ماشین‌ها ویژگی رنگ و چرخ دارند. اما خودروهای گازی، یک کپسول گاز و سیستم گازسوز اضافه بر سایر خودروها دارند. همین قضیه برای مثال حیوانات هم برقرار است.

در برنامه نویسی شئ گرا وقتی ویژگی‌ها و متدهای زیادی بین دو (یا چند) کلاس مشترک هستند، معمولاً  یک کلاس بزرگ‌تر حاوی موارد مشترک در نظر گرفته و کلاس‌ها زیرمجموعه را از آن ارث‌بری می‌کنند.

مشابه دنیای واقعی که هر فرزند تقریباً همه ویژگی‌های والدین خود را به ارث می‌برد، در برنامه‌نویسی نیز به همین شکل است. برخی از ویژگی‌های ارث گرفته در فرزند ممکن است تقویت یا تضعیف شده باشد و همچنین یک فرزند خصوصیات غیر مشترکی هم با والدین خود دارد. این قضیه در ارث‌بری برنامه‌نویسی شئ‌گرا نیز برقرار است.

ارث بری در برنامه نویسی

مثال برنامه شئ گرا مدیریت دانشگاه را در نظر بگیرید. در این برنامه، استاد، دانشجو و کارمند همگی از کلاس انسان هستند ولی تفاوت‌هایی در ویژگی‌ها و رفتارهای خود دارند؛ مثلاً:

  • استاد می‌تواند نمره درس را تعریف کند ولی دو نوع دیگر نمی‌توانند.
  • دانشجو می‌تواند درس را اخذ کند ولی این کار برای دو نوع دیگر معنایی ندارد.
  • یک کارمند چیزی به نام ساعت حضور و غیاب دارد که دانشجویان ندارند.
  • دانشجو دارای شماره دانشجویی است ولی استاد و کارمند دارای کد پرسنلی هستند که ممکن است ساختارش متفاوت باشد.

در این حالت در برنامه نویسی شیء گرا، ما یک کلاس کلی از نوع انسان ایجاد می‌کنیم که دارای متدها و خصیصه‌های مشترک است؛ یعنی راه می‌رود، حرف می‌زند و دارای نام، کد ملی و تاریخ تولد است. سپس کلاس‌های استاد و دانشجو از این کلاس ارث‌بری کرده تا توانایی‌های مخصوصشان پیاده‌سازی شود.

بسته به نیاز سیستم، احتمالاً استاد یک نوع کارمند در دانشگاه است.برای اینکه مفهوم ارث‌بری در برنامه‌نویسی را بهتر متوجه شوید، سعی کنید در زندگی روزمره خود مثال‌هایی برای آن پیدا کرده و آن‌ها را تعمیم دهید.

مفهوم چند ریختی

چندریختی (Polymorphism : بخوانید پُلی مورفیسم) به ما اجازه می‌دهد که متد دارای اجراهای مختلفی باشد. دو نوع چند ریختی در برنامه نویسی شئ گرا داریم. که در این بخش به طور مختصر با آن‌ها آشنا می‌شویم.

چند ریختی با Method Overriding : فرض کنید کلاسی برای شکل‌های هندسی داریم که یک متد رسم (draw()) دارد. کلاس‌های مستطیل، پنج ضلعی و دایره از این کلاس ارث‌بری کرده و چون نحوه رسمشان متفاوت است، این متد را بازنویسی می‌کنند.

بازنویسی متد در برنامه نویسی شیءگرا
بازنویسی متد در برنامه نویسی شیءگرا

چند ریختی با Method Overloading : در این حالت در برنامه نویسی شئ گرا از ارث‌بری خبری نیست. همچنین نام متد و نوع خروجی آن (امضا) تغییری نمی‌کند. صرفاً چند متد مشابه با آرگومان‌ها (پارامترهای ورودی) متفاوت در اختیار داریم.

فرض کنید می‌خواهیم کلاس دایره را به گونه‌ای پیاده‌سازی کنیم که اگر draw() صدا زده شد، دایره‌ای با شعاع تصادفی و در صورت تعیین کردن اندازه در ورودی (draw(x)) دایره را با شعاع مورد نظر رسم کند. شبه کد ما چیزی شبیه به زیر می‌شود:

مثال overloading چند ریختی کلاس‌ها
مثال overloading چند ریختی کلاس‌ها

خلاصه مفاهیم برنامه نویسی شی گرا

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

در این آموزش با زبانی ساده با مبانی برنامه نویسی شئ گرایی آشنا شدیم. مفهوم کلاس، شئ، ویژگی و متد را فهمیده و با ۴ اصل اساسی آن را بررسی کردیم.

اگر می‌خواهید در مورد تاریخچه شکل‌گیری زبان‌های برنامه نویسی شئ گرا بخوانید، در ویکی‌پدیا اطلاعات مختصر و مفیدی ارائه داده است.

امیدوارم این آموزش به فهم بهتر مفاهیم کمک کرده باشد. اگر سؤالی دارید، از بخش دیدگاه‌ها بپرسید.