جلسه شماره 115رایگان

Telescoping Constructor | تلسکوپینگ کانستراکتور

00:14:30

توضیحات جلسه

🎥 این ویدیو دومین قسمت از پلی‌لیست بررسی کتاب Effective Java است. 📚 در این جلسه سراغ Item 2 کتاب افکتیو جاوا می‌رویم: Consider a Builder When Faced with Many Constructor Parameters در این بخش با Telescoping Constructor یا تلسکوپینگ کانستراکتور آشنا می‌شویم؛ روشی که برای ساخت آبجکت‌هایی با تعداد زیادی پارامتر ضروری و اختیاری، چندین Constructor با ورودی‌های متفاوت تعریف می‌کند. در این جلسه یاد می‌گیریم: 🔍 تلسکوپینگ کانستراکتور چیست و چگونه پیاده‌سازی می‌شود 🏗️ نحوه ساخت Instance با Constructorهای چندپارامتری ⚠️ بررسی معایب این روش مانند کاهش خوانایی و دشواری تشخیص پارامترها 📈 مشکلات نگهداری و توسعه کد با افزایش تعداد فیلدها 🧠 ارزیابی کلی Telescoping Constructor و ضرورت استفاده از راهکاری بهتر مانند Builder اگر در حال یادگیری برنامه‌نویسی حرفه‌ای جاوا، طراحی کلاس‌ها و روش‌های اصولی ساخت آبجکت هستید، این ویدیو به شما کمک می‌کند مشکلات Constructorهای چندپارامتری را بهتر درک کنید. 📌 یوتیوب: youtube.com/@farzadafi 📌 آپارات: aparat.com/farzadafi 📌 وب‌سایت: https://farzadafi.ir 💬 گروه پرسش و پاسخ تلگرام: @programmingByFarzadAfi 💬 گروه پرسش و پاسخ بله: @programming_by_farzadafi هر سؤالی داشته باشید می‌توانید داخل گروه مطرح کنید تا من یا مربی‌های حاضر در گروه کمکتان کنیم 💬

جزوه و مستندات

مفاهیم کلیدی

  • Telescoping Constructor Pattern

الگویی برای ساخت objectهایی با پارامترهای متعدد است. در این الگو یک constructor فقط پارامترهای اجباری را دریافت می‌کند و constructorهای بعدی به‌ترتیب پارامترهای اختیاری بیشتری می‌پذیرند تا در نهایت تمام پارامترها پوشش داده شوند.

  • Required Parameters

مقادیر ضروری برای ایجاد یک object معتبر هستند. در کلاس NutritionFacts، فیلدهای servingSize و servings پارامترهای اجباری محسوب می‌شوند.

  • Optional Parameters

مقادیری هستند که تعیین آن‌ها هنگام ساخت object الزامی نیست و می‌توانند مقدار پیش‌فرض داشته باشند. فیلدهای calories، fat، sodium و carbohydrate در مثال، اختیاری هستند.

  • Constructor Chaining

فراخوانی یک constructor از داخل constructor دیگر با استفاده از this(...) است. این روش منطق مقداردهی را در کامل‌ترین constructor متمرکز کرده و از تکرار کد جلوگیری می‌کند.

  • Default Value

مقداری است که در صورت تعیین‌نشدن یک پارامتر اختیاری استفاده می‌شود. در مثال NutritionFacts، مقدار پیش‌فرض پارامترهای اختیاری برابر 0 در نظر گرفته شده است.

  • Shortest Applicable Constructor

در الگوی telescoping constructor، کلاینت کوتاه‌ترین constructorای را انتخاب می‌کند که تمام پارامترهای موردنیازش را پوشش دهد. بااین‌حال ممکن است برای رسیدن به یک پارامتر انتهایی، مجبور شود مقادیر پارامترهای اختیاری قبلی را نیز ارسال کند.

  • Parameter Order Dependency

در constructorهای چندپارامتری، معنای هر مقدار به موقعیت آن وابسته است. بنابراین کلاینت باید ترتیب پارامترها را دقیقاً بداند و رعایت کند.

  • Positional Arguments

آرگومان‌هایی هستند که معنا و مقصدشان فقط بر اساس موقعیت آن‌ها در فراخوانی مشخص می‌شود. در کدی مانند new NutritionFacts(240, 8, 100, 0, 35, 27)، بدون مشاهده‌ی امضای constructor نمی‌توان معنای هر عدد را به‌سادگی تشخیص داد.

  • Identically Typed Parameters

پارامترهای متوالی با نوع یکسان هستند. اگر چند پارامتر همگی از نوع int باشند، جابه‌جایی اشتباه آن‌ها توسط compiler شناسایی نمی‌شود؛ زیرا امضای فراخوانی همچنان معتبر است.

  • Client Code Readability

میزان قابل‌فهم‌بودن کدی است که از یک API استفاده می‌کند. constructorهای طولانی با آرگومان‌های عددی متعدد، خوانایی کد کلاینت را کاهش می‌دهند.

  • Scalability Problem

الگوی telescoping constructor برای تعداد کم پارامترها قابل‌استفاده است، اما با افزایش پارامترهای اختیاری، تعداد constructorها و پیچیدگی استفاده از آن‌ها به‌سرعت افزایش می‌یابد.

  • Immutable Object Initialization

در مثال، تمام فیلدها با final تعریف شده‌اند و در زمان ساخت مقدار می‌گیرند. این طراحی امکان ایجاد object تغییرناپذیر را فراهم می‌کند، اما انتخاب روش مناسب برای ارسال پارامترهای متعدد اهمیت زیادی دارد.

موارد مصاحبه ای

  • الگوی Telescoping Constructor چیست؟

روشی است که در آن چند constructor با تعداد افزایشی از پارامترها تعریف می‌شوند؛ از پارامترهای اجباری شروع شده و به همه‌ی پارامترهای اختیاری ختم می‌شوند.

  • چرا Telescoping Constructor Pattern مقیاس‌پذیر نیست؟

زیرا با افزایش پارامترهای اختیاری، تعداد constructorها بیشتر می‌شود و نوشتن، خواندن و نگهداری کد دشوارتر خواهد شد.

  • Constructor Chaining چگونه انجام می‌شود؟

با استفاده از this(...)، یک constructor پارامترهای خود و مقادیر پیش‌فرض را به constructor کامل‌تر ارسال می‌کند.

  • مزیت Constructor Chaining چیست؟

منطق مقداردهی فیلدها را در یک محل متمرکز می‌کند، تکرار کد را کاهش می‌دهد و تغییر مقادیر پیش‌فرض را ساده‌تر می‌سازد.

  • مشکل اصلی فراخوانی constructorهای طولانی چیست؟

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

  • چرا جابه‌جایی دو پارامتر هم‌نوع خطرناک است؟

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

  • آیا استفاده از مقدار پیش‌فرض مشکل Telescoping Constructor را کاملاً حل می‌کند؟

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

  • تفاوت پارامتر اجباری و اختیاری چیست؟

پارامتر اجباری برای ساخت یک object معتبر ضروری است، اما پارامتر اختیاری می‌تواند تعیین نشود و مقدار پیش‌فرض دریافت کند.

  • چرا استفاده‌ی گسترده از پارامترهای int در یک constructor نامناسب است؟

زیرا همه‌ی آرگومان‌ها از نظر نوع یکسان‌اند و compiler نمی‌تواند خطاهای معنایی ناشی از جابه‌جایی آن‌ها را تشخیص دهد.

  • چه زمانی Telescoping Constructor قابل‌قبول است؟

زمانی که تعداد پارامترها کم، ترتیب آن‌ها واضح و احتمال افزایش پارامترهای اختیاری در آینده پایین باشد.

سناریو کاربردی

  • تعریف اطلاعات تغذیه‌ای محصول

کلاس NutritionFacts شامل دو فیلد اجباری و چهار فیلد اختیاری است:

  • servingSize: اندازه‌ی هر وعده
  • servings: تعداد وعده‌ها در بسته
  • calories: کالری هر وعده
  • fat: چربی هر وعده
  • sodium: سدیم هر وعده
  • carbohydrate: کربوهیدرات هر وعده

برای پشتیبانی از ترکیب‌های مختلف پارامترها، چند constructor تعریف می‌شود. هر constructor با استفاده از this(...)، پارامترهای موجود و مقدار پیش‌فرض 0 را به constructor بعدی ارسال می‌کند. کامل‌ترین constructor تمام فیلدها را مقداردهی می‌کند.

  • ساخت نمونه برای محصول
NutritionFacts cocaCola =
    new NutritionFacts(240, 8, 100, 0, 35, 27);

این فراخوانی به‌ترتیب، اندازه‌ی وعده، تعداد وعده‌ها، کالری، چربی، سدیم و کربوهیدرات را تعیین می‌کند.

  • مشکل خوانایی

از روی مقادیر 240، 8، 100، 0، 35 و 27 نمی‌توان بدون مراجعه به امضای constructor تشخیص داد که هر عدد متعلق به کدام ویژگی است. کلاینت باید پارامترها را بشمارد و ترتیب آن‌ها را به خاطر بسپارد.

  • مشکل پارامترهای ناخواسته

اگر کلاینت بخواهد sodium و carbohydrate را تعیین کند ولی تمایلی به تعیین fat نداشته باشد، همچنان باید مقدار پیش‌فرض 0 را برای fat ارسال کند.

  • خطر خطای زمان اجرا

اگر کلاینت دو آرگومان int مانند sodium و carbohydrate را جابه‌جا کند، کد بدون خطای compile-time کامپایل می‌شود؛ اما اطلاعات تغذیه‌ای اشتباه ثبت خواهد شد.

بیشتر بدانید

  • نکته‌ی طراحی API

از تعریف constructorهایی با تعداد زیاد پارامتر، به‌ویژه پارامترهای هم‌نوع، خودداری کنید؛ زیرا احتمال استفاده‌ی اشتباه از API را افزایش می‌دهد.

  • نکته‌ی خوانایی

فراخوانی زیر از نظر نحوی معتبر است، اما معنای آرگومان‌ها را منتقل نمی‌کند:

new NutritionFacts(240, 8, 100, 0, 35, 27);

هرچه تعداد مقادیر بیشتر باشد، بررسی و نگهداری این کد دشوارتر می‌شود.

  • نکته‌ی مقدار پیش‌فرض

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

  • نکته‌ی جایگزین

برای کلاس‌هایی با پارامترهای اجباری و اختیاری متعدد، الگوی Builder معمولاً گزینه‌ای خواناتر و ایمن‌تر از Telescoping Constructor Pattern است.

  • نکته‌ی اعتبارسنجی

متمرکزکردن مقداردهی در کامل‌ترین constructor امکان انجام validation یکپارچه را فراهم می‌کند؛ مانند جلوگیری از مقدار منفی برای calories یا sodium.

  • نکته‌ی خطای معنایی

compiler فقط سازگاری نوع‌ها را بررسی می‌کند و معنای مقادیر را نمی‌داند. بنابراین دو آرگومان هم‌نوع ممکن است بدون خطای کامپایل جابه‌جا شوند و یک logic bug ایجاد کنند.