قبل از اینکه توضیح بدیم اصلا Object Oriented Programming برای چی وجود داره، قبلش درباره این صحبت کنیم که اصلا OOP داره جه مسئله ای رو حل میکنه؟
۱. شروع پیچیدگی های نرم افزار
قبل از OOP اکثر نرم افزار های با زبان های برنامه نویسی Procedural نوشته میشدن مثل C و Fortran که تمرکز اصلیشون رو روی نوشتن function ها و procedures ها میزاشتن تا دیتا رو manipulate بکنند. حالا شاید از خودتون بپرسید procedureها چی هستن؟ manipulate کردن دیتا ینی چی؟
Procedure ینی چی؟
Procedureها بسته به زبان برنامه نویسی که داریم استفاده میکنیم function یا subroutine هم گفته میشن که یک بلاکی از کد هستش که یک تسک خاص رو انجام میده، Procedure ها به ما کمک میکنن که تا ما کدهامون دسته بندی کنیم تا یه سری کارو برای ما انجام بدن، برای مثال اگه ما بخواهیم دو تا عدد رو با هم جمع بکنیم به جای کد زیر هر جای بیاییم تکرارش بکنیم:
sum = a + b;
تسک بالا رو میاییم و یک functionش میکنیم تا بتونیم هر جایی که بخواهیم استفاده بکنیم (کد پایین به زبان برنامه نویسی C نوشته شده):
#include <stdio.h>
void addNumbers(int a, int b) {
int sum = a + b;
printf("Sum is: %d\n", sum);
}
int main() {
addNumbers(5, 10);
return 0;
}
Manipulate کردن دیتا ینی چی؟
Manipulate کردن به پروسه ای گفته میشه که ما دیتارو تغییر میدیم مثل sort کردن، فیلتر کردن، تغییر دادن تو مقادیر، aggregate کردن و …
وقتی که application که با زبان های برنامه نویسی Procedural نوشته شده بودن شروع به بزرگ شدن میگردن و پیچیدگی های بیشتری داخل این application ها وارد میشد ما یه سری محدودیت هارو میدیدیم:
- Reusability ضعیف: از اونجایی که توی زبان های برنامه نویسی Procedural کدها به functionها مختلف تقسیم شدن و روی یک دیتای global کار میکنن، زمانی که پروژه بزرگ میشد خیلی سخت میشد که این کدهارو دوباره استفاده کرد چون خیلی گره خورده بودن به ساختار اون دیتای global، هر requirement جدیدی که معرفی میشد داخل نرم افزار برنامه نویس ها مجبور بودن کد رو کپی کنن و همین باعث میشد که ما کدهای تکراری یا به اصطلاح duplicated codeهای زیادی رو ببینیم.
- دشوار شدن Maintenance کردن پروژه: وقتی که application ما scale میکرد maintenance کردن پروژه خیلی سخت میشد چون یک تغییر کوچیک توی بخشی از پروژه باعث میشد تاثیر مخربی توی بخش های دیگه ای از پروژه داشته باشه
- نرسیدن به Modularity: با برنامه نویسی procedural خیلی سخت میشد که ما به modularity درست برسیم (این که modularity درست چی هست هم یه بحث بزرگ دیگه ایه) برسیم
سر همین مواردی که اشاره کردم OOP معرفی شد تا بتونه این مشکلات رو با معرفی مفاهیمی مثل data abstraction، modularity و code reuse حل بکنه.
۲. مفاهیمی که OOP با خودش معرفی کرد تا بتونیم چالش های مهندسی نرم افزار رو حل بکنیم
Abstraction
انتزاع (Abstraction) یعنی پنهان کردن جزئیات غیرضروری و فقط در معرض قرار دادن چیزهایی که مرتبط و مهم هستن. توی برنامهنویسی شیگرا، این معمولاً به این معناست که اشیاء طوری طراحی بشن که بخشهای داخلی و نحوهی کارکردشون مخفی بمونه و بقیهی قسمتهای برنامه فقط از طریق رابط عمومیشون (مثل متدها و ویژگیهایی که قرار هست در دسترس باشن) با اونها تعامل کنن.
یکی از دلایل اصلی بوجود اومدن برنامهنویسی شیگرا اینه که رابطههای پیچیده بین دادهها و عملیات رو ساده تر کنه. این کار با abstract کردن همه چیز توی “object”های مستقل انجام میشه. هر object نمایندهی یه موجودیت دنیای واقعی مثل Car، Customer یا Bank Account و دادهها (attributes) و رفتارها (methods) رو کنار هم نگه میداره. اینطوری شفافیت و تمرکز بیشتر میشه، چون فقط لازمه بدونی اون object چی کار میکنه، نه اینکه دقیقاً چطوری انجامش میده.
آلن کی (Alan Kay)، کسی که به عنوان خالق برنامهنویسی شیگرا شناخته میشه، یه جمله معروف داره:
«هدف این بود که برنامهها قابل فهم تر و قابل مدیریت تر بشن، تا اونا رو به صورت مجموعهای از objectهایی که با هم تعامل دارن، ساختاربندی کنیم.»
Encapsulation
Encapsulation به این معنیه که دادهها (attributes) و متدها (توابعی که روی اون دادهها کار میکنن) رو توی یه واحد به نام «Object» کنار هم جمع کنیم.
این کار باعث میشه بخشهای داخلی object محافظت بشن و دسترسی به بعضی قسمتها محدود بشه. به همین خاطر برنامهنویس میتونه ساختار داخلی رو تغییر بده بدون اینکه روی رابط بیرونی object تأثیری بذاره.
این مفهوم امنیت داده و نگهداری کد رو بهتر میکنه و اجازه میده تغییرات داخلی انجام بدیم بدون اینکه ترسی از خراب شدن کارکرد بیرونی داشته باشیم.
گرادی بوچ (Grady Booch) توی کتابش به نام «Object-Oriented Analysis and Design» میگه:
«کپسولهسازی باعث میشه وابستگی بین اجزای سیستم کمتر بشه و در نتیجه سیستمها انعطافپذیرتر و راحتتر برای بهروزرسانی یا گسترش باشن.»
Inheritance
Inheritance این امکان رو میده که یک کلاس، ویژگیها و متدهای کلاس دیگهای رو به ارث ببره. یعنی میتونیم یه کلاس جدید بسازیم و بدون اینکه مجبور بشیم دوباره همون کدها رو تکرار کنیم، از کدهای کلاس موجود استفاده کنیم.
این قابلیت استفادهی مجدد از کد رو تشویق میکنه و یکی از دلایل اصلیه که برنامهنویسی شیگرا رو برای ساخت سیستمهای بزرگ کارآمد و مؤثر میکنه. (البته باز باید توی استفاده از inheritance حواسمون باشه که باز این یک مبحث بزرگ دیگه ایه)
برتراند مایر (Bertrand Meyer) توی کتابش به نام «Object-Oriented Software Construction» توضیح میدهه که ارث بری باعث بوجود اومدن Generalization میشه؛ چیزی که هم تکرار بیهودهی کد رو کم میکنه و هم یه سلسله مراتب طبیعی از موجودیتها توی سیستم ایجاد میکنه.
برای مثال، یه کلاس «Car» میتونه از کلاس «Vehicle» ارث بری کنه.
Polymorphism
Polymorphism این امکان رو میده که یک interface واحد بتونه شکلها و رفتارهای متفاوتی رو نشون بده. به زبان سادهتر، متدها میتونن بسته به objectی که روی اون فراخوانی میشن، رفتار متفاوتی داشته باشن.
در اصل، Polymorphism این فرصت رو فراهم میکنه که با objectهای مختلف به یه شکل یکسان برخورد کنیم، در حالی که پشت صحنه هر کدوم میتونن عملکرد مخصوص به خودشون رو داشته باشن. این ویژگی باعث میشه کد هم انعطافپذیرتر باشه و هم راحتتر توسعه پیدا کنه.
رابرت لافور (Robert Lafore) توی کتاب «Object-Oriented Programming in C++» توضیح میده که Polymorphism باعث سادهتر شدن تعامل با objectهای مختلف میشه و همین موضوع سیستمها رو پویاتر و انعطافپذیرتر میکنه.
۳. OOP بهعنوان یه پارادایم طبیعی برای مدلسازی سیستمهای دنیای واقعی
یکی دیگه از دلایل اصلی شکلگیری برنامهنویسی شیگرا اینه که با نحوهی درک ما از دنیای اطرافمون هماهنگه. توی دنیای واقعی، ما با اشیائی سروکار داریم که هم «ویژگی» (attributes) دارن و هم «رفتار» (methods).
OOP همین نگاه رو به برنامهنویسی میاره و باعث میشه طراحی و فهم سیستمها طبیعیتر و نزدیکتر به واقعیت باشه.
برای مثال، یه آبجکت «Car» میتونه ویژگیهایی مثل رنگ، برند و مدل داشته باشه و رفتارهایی مثل رانندگی کردن و توقف کردن رو انجام بده.
برنامهنویسی شیگرا این امکان رو به توسعهدهندهها میده که نرمافزارشون رو به شکل نزدیک به موجودیتهای واقعی مدلسازی کنن، که باعث میشه فرآیند طراحی و توسعه طبیعیتر و قابلفهمتر باشه.
همچنین این موضوع ارتباط بین توسعهدهندهها و ذینفعان رو بهتر میکنه، چون مفاهیمی که توی سیستم استفاده میشن راحت تر با دنیای واقعی همخوانی پیدا میکنن.
ایوار یاکوبسون (Ivar Jacobson) توی کتابش «Object-Oriented Software Engineering» تأکید میکنه که اشیاء میتونن بهطور طبیعی نمایندهی موجودیتهای دنیای کسبوکار باشن. با مدل سازی این موجودیتهای واقعی، برنامهنویسی شیگرا به ذینفعان کمک میکنه تا سیستم نرمافزاری رو بهتر و راحتتر درک کنن.
4. نقش برنامهنویسی شیگرا در سیستمهای بزرگ و نگهداری بلندمدت
برنامهنویسی شیگرا برای نگهداری بلندمدت سیستم و همکاری بین تیمها بسیار مفیده. توی سیستمهای بزرگ که چندین توسعهدهنده روی بخشهای مختلف کار میکنن، OOP ساختار واضحی فراهم میکنه که هر توسعهدهنده میتونه روی اشیاء خاص و تعاملاتشون تمرکز کنه.
این موضوع برای تیمهایی که روی پروژههای بزرگ کار میکنن حیاتی هست، چون سیستم رو میشه به قطعات قابل مدیریت تقسیم کرد.
رابرت سی مارتین (Robert C. Martin) توی کتابش «Clean Code» بهطور مفصل درباره اهمیت اصول شیگرایی مثل Cohesion ( عملکردهای مرتبط داخل یک شیء) و Loose Coupling (اشیاء مستقل) صحبت میکنه و توضیح میده که این اصول چطور باعث میشن سیستمها در طول زمان قابل نگهداری تر باشن.
نتیجه گیری از اینکه چرا OOP وجود داره
- برای مدیریت پیچیدگی: برنامهنویسی شیگرا مفاهیمی معرفی میکنه که مدیریت سیستمهای پیچیده رو بهتر میکنن.
- برای بهبود ماژولار بودن: با کپسوله کردن دادهها و رفتارها داخل اشیاء، OOP ساختار واضح تر و منظمتری ایجاد میکنه.
- برای استفاده مجدد از کد: ارثبری اجازه میده کدهای موجود بدون تکرار گسترش پیدا کنن.
- برای مدلسازی سیستمهای دنیای واقعی: OOP نرمافزار رو طبیعیتر و قابلفهمتر میکنه چون موجودیتهای واقعی رو شبیهسازی میکنه.
با هم راستا کردن کد با مفاهیم دنیای واقعی و تأکید بر ماژولار بودن، استفاده مجدد و کپسولهسازی، برنامهنویسی شیگرا پیچیدگی فزاینده سیستمهای نرمافزاری رو مدیریت میکنه و به همین دلیل یه تکامل طبیعی نسبت به پارادایمهای قبلیه.