درس 11 از 33
در حال پیشرفت

سفری به دنیای شیء گرایی

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

آشنایی با دو رقیب:

سارا: یه برنامه‌نویس که سرش تو روش‌های دستوری (procedural) بود و معتقد بود همه‌چیز باید ساده، جمع‌وجور و بی‌دردسر باشه. تو ذهنش کد نوشتن یعنی زدن یه‌راست به هدف، بدون اینکه وقتو تلف طراحی و فلسفه‌بافی کنی.

امیر: یه برنامه‌نویس با استایل شیءگرا (OO)، همیشه درگیر طراحی معماری و ساختن کدهای تمیز و انعطاف‌پذیر. براش نوشتن کد بیشتر شبیه خلق یه اثر هنری بود تا یه کار روتین.

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

سارا: تفکر دستوری

سارا پشت میزش لم داد، یه نفس عمیق کشید و با خودش گفت:
“خب، این برنامه قراره چه کارایی بکنه؟”
کمی فکر کرد و ادامه داد:
“واضحه… باید بچرخه و صدا پخش کنه.”

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

				
					rotate(shapeNum) {  
  // کاری کن که شکل 360 درجه بچرخه  
}  
playSound(shapeNum) {  
  // از shapeNum برای پیدا کردن صدای AIF استفاده کن و پخشش کن  
}

				
			

امیر: طراحی شیءگرا

امیر خونسردتر از این حرف‌ها بود که بخواد عجله کنه. تو یه کافه دنج نشسته بود، با یه لیوان قهوه کنارش، و داشت تو دفترش چیزایی می‌نوشت.
“خب، این برنامه از چه اجزایی تشکیل شده؟” با خودش فکر کرد.

ذهنش پر کشید سمت مفاهیمی مثل “اشکال” (Shapes)، “کاربر” (User)، و “صدا” (Sound). برای امیر، هر چیزی توی برنامه باید مثل یه قطعه از پازل باشه که جای خودش رو تو کل ساختار پیدا می‌کنه.

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

“برنامه خوب، یعنی پایه محکم و ساختار درست.” این جمله همیشه تو ذهنش بود.

تغییر مشخصات: ورود «چرخنده»

همه‌چیز داشت خوب پیش می‌رفت که مدیر پروژه اومد و گفت:
“یه تغییر کوچیک داریم: باید یه شکل جدید به اسم چرخنده اضافه کنیم. وقتی کاربر روش کلیک کرد، باید مثل بقیه بچرخه، ولی فایل صدای اون .mp3 باشه و نه .AIF. ضمن اینکه چرخشش باید دور یه نقطه خاص باشه، نه مرکز مستطیلش.”

این تغییر، چالش بزرگی برای هر دو برنامه‌نویس ایجاد کرد.

واکنش سارا: راه‌حل دستوری

سارا که به روش دستوری عادت داشت، بدون معطلی تصمیم گرفت کدش رو با اضافه کردن یک if/else جدید به‌روزرسانی کنه. برای اینکه نقطه چرخش «چرخنده» رو تغییر بده، دستی مقادیر جدید رو وارد کرد و برای هر تغییر کوچیک، کدهای بیشتری نوشت. او به خوبی می‌دونست که این روش، کار تست و رفع اشکال رو پیچیده‌تر و زمان‌برتر می‌کنه، ولی با این حال، تصمیم گرفت تا از همین راه ادامه بده چون به روش خودش اعتماد داشت.

واکنش امیر: انعطاف شیءگرا

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

با لبخندی روی لب، امیر گفت: “انعطاف‌پذیری یعنی همین! اینجا شیءگرایی قدرت خودش رو نشون می‌ده.”

سارا و امیر درگیر بحثی داغ شدند.

سارا: “امیر، توی کدت یه عالمه تکرار داری! مثلاً این پروسه چرخش توی همه‌ی اشکال هست.”
امیر: “اولاً، بهش می‌گن متد، نه پروسه! و دوماً، اینا کلاس هستن، نه چیز دیگه!”
سارا: “هر چی که هست، طراحیت اصلاً بهینه نیست. چطور می‌تونی چهار نسخه‌ی مختلف متد چرخش رو نگه داری؟”

اینجا بود که امیر با لبخندی مطمئن گفت: “بذار بهت نشون بدم وراثت (Inheritance) توی شیءگرایی چطور به کار میاد.”

طراحی امیر

امیر توضیح داد که همه‌ی اشکال (دایره، مربع، مثلث و چرخنده) ویژگی‌های مشترکی دارند. بنابراین تصمیم گرفت این ویژگی‌ها را به یک کلاس کلی‌تر به نام Shape (شکل) منتقل کند. به این ترتیب، متدهای “چرخش” و “پخش صدا” فقط یک بار در کلاس اصلی تعریف شدند و کلاس‌های دیگر این ویژگی‌ها را از آن به ارث بردند.

ساختار کد:

کلاس اصلی (Superclass):

				
					class Shape {  
  void rotate() {  
    // کد چرخش عمومی  
  }  
  void playSound() {  
    // کد پخش صدا  
  }  
}  
				
			

کلاس‌های فرعی (Subclasses):

				
					class Circle extends Shape { }

class Square extends Shape { }

class Triangle extends Shape { }

class SpinningShape extends Shape {
    // متد چرخش اختصاصی برای چرخنده
    void rotate() {
        // کد چرخش خاص برای چرخنده
    }

    // متد پخش صدا اختصاصی برای چرخنده
    void playSound() {
        // کد پخش صدای MP3 برای چرخنده
    }
}

				
			

بحث درباره Override (بازنویسی)

سارا: “ولی یه مشکل هست. چرخنده می‌خواد یه رفتار خاص برای چرخش و صدای خودش داشته باشه. وقتی از کلاس Shape ارث‌بری کرده، چطور می‌خوای این رفتارها رو تغییر بدی؟”

امیر: “اینجا دقیقاً بازنویسی (Override) به کار میاد.”

او توضیح داد که کلاس‌های فرعی می‌توانند متدهای کلاس اصلی را دوباره تعریف کنند. به این ترتیب، چرخنده نسخه‌ی خودش از متدهای “چرخش” و “پخش صدا” را دارد و رفتار متفاوتی از بقیه‌ی اشکال نشان می‌دهد.

پلی‌مورفیسم (Polymorphism) در عمل

امیر گفت: “حالا فرض کن موقع اجرای برنامه (Runtime) به شیء چرخنده بگیم بچرخ. ماشین مجازی جاوا (JVM) به صورت خودکار می‌فهمه که باید کد چرخش خاص چرخنده رو اجرا کنه، نه کد عمومی Shape. این یعنی انعطاف‌پذیری فوق‌العاده در طراحی کد، که بهش می‌گن چندریختی (Polymorphism).”

آخرش کی برد؟

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

پی‌نوشت: در پایان، نرگس نه تنها صندلی ارگونومیک و میز تنظیم‌شونده رو برد، بلکه مدیر پروژه تصمیم گرفت از این به بعد کدنویسی شیءگرا رو به همه‌ی اعضای تیم آموزش بده!