بازسازی کد: استخراج متد (Extract method)
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: چهار دقیقه

در این بازسازی، با قطعه کدی روبرو هستیم که می‌توانیم آن را به صورت یک متد جدید، گروه‌بندی کنیم. نام متد، توضیح دهنده عملیاتی است که توسط آن قطعه کد انجام می‌شود. 
این بازسازی یکی از پر استفاده‌ترین بازسازی‌های کد است. معمولا زمانیکه متدی بلند باشد یا تکه کدی نیاز به کامنتی برای توضیح درباره کاری که انجام می‌دهد داشته باشد، چنین بازسازی ای نیاز است. در صورتیکه نام متدها به طور مناسبی انتخاب شوند، ایجاد متدهای کوچک از دو جهت مفید است: 
  1. خواندن متن متدهای بالادستی را آسان‌تر می‌کند. در واقع نام متد عملا نقش کامنت را ایفا می‌کند. مراجعه کنید به Self documenting code  
  2.  احتمال اینکه متدها دوباره استفاده شوند را بالا می‌برد

الگوهای متفاوتی در مورد طول متدها وجود دارد. ولی قاعده کلی حاکم بر این مورد «ارتباط منطقی بدنه و نام متد» است. در صورت رعایت این قاعده، عموما متدهایی با اندازه مناسب به‌وجود می‌آیند. 
به‌طور مثال قطعه کد زیر را مشاهده کنید:  
public void PrintInfo(dynamic person)
{ 
       Console.WriteLine(person.Name); 
       Console.WriteLine(person.LastName); 
       Console.WriteLine(person.Job.Title); 
       Console.WriteLine(person.Job.Salary); 
} 
این قطعه کد را می‌توان به صورت زیر بازسازی کرد:
public void PrintInfo(dynamic person) 
{ 
       Console.WriteLine(person.Name); 
       Console.WriteLine(person.LastName); 
       PrintJob(person.Job); 
} 
public void PrintJob(dynamic job) 
{ 
       Console.WriteLine(job.Title); 
       Console.WriteLine(job.Salary); 
}


مراحل انجام این بازسازی کد 

بعد از تشخیص تکه کدی که نیاز به استخراج متد در آن وجود دارد، مراحل زیر را انجام دهید:
  1. متد جدیدی ایجاد کنید و نام آن را بر اساس کاری که قرار است تکه کد انتخاب شده انجام دهد، تعیین کنید (نام را بر اساس کاری که قرار است انجام دهد انتخاب نمایید؛ نه نحوه انجام دادن آن کار).
  2. تکه کد نیازمند استخراج را از بدنه متد قبلی به بدنه متد جدید کپی کنید.
  3. کد استخراج شده را برای پیدا کردن متغیرهای محلی به‌جا مانده از متد اصلی بررسی کنید. این متغیرها احتمالا متغیرهای محلی متد جدید و پارامترهای آن را تشکیل خواهند داد. 
  4. اگر متغیرهای محلی موجود در تکه کد استخراج شده فقط در آن استفاده شده‌اند، آن‌ها را به صورت متغیرهای محلی موقتی در متد جدید ایجاد کنید. 
  5. متغیرهای محلی تکه کد استخراج شده را بررسی کنید که آیا در جایی از آن ویرایش شده‌اند یا خیر؟ در صورتیکه ویرایش شده باشند، بررسی کنید که آیا می‌توان آن را به عنوان خروجی متد جدید در نظر گرفت و متغیرها را مقداردهی کرد یا خیر؟ (توضیح بیشتر در مثال) 
  6. پارامترهای متناظری را با متغیرهای محلی موقتی ایجاد شده، در متد جدید ایجاد کنید.
  7. بعد از این که تکلیف تمامی متغیرهای محلی مشخص شد، کد را کامپایل کنید.
  8. در متد مبدا تکه کد استخراج شده را به فراخوانی متد جدید تغییر دهید.
  9. کد را کامپایل و تست کنید .

مثال: تکه کدی با ویرایش کردن متغیرهای محلی 
ساده‌ترین حالتیکه کد استخراج شده از متغیرهای محلی متد مبدا استفاده می‌کند زمانی است که تنها مقادیر این متغیرها را می‌خواند. مثال ذکر شده در ابتدای نوشتار از این نوع است.
زمانی که متغیری در تکه کد استخراج شده ویرایش شده باشد، معمولا با دو حالت روبرو هستیم:
  • متغیر ویرایش شده فقط در تکه کد استخراج شده ویرایش و استفاده شده‌است.
  • متغیر ویرایش شده بعد از تکه کد استخراج شده نیز در بدنه متد اصلی مورد استفاده قرار گرفته‌است.
در حالت دوم نیاز است مقدار متغیر ویرایش شده، به متد بالادستی برگردانده شود. به طور مثال تکه کدی را در نظر بگیرید که مقدار رقم نهایی قابل پرداخت یک آیتم سفارش را در آن مقداردهی می‌کند. این روال را می‌توان به صورت زیر پیاده سازی کرد:
public void SetPayableAmount(dynamic orderItem) 
{ 
        var price = orderItem.Price; 
        var discount = 0; 
        var discountPlan = GetDiscountPlan(); 
        var discountPercentage = discountPlan.Percentage; 
        discount = price * discountPercentage; 
        orderItem.PayableAmount = orderItem.Price - discount 
} 
private dynamic GetDiscountPlan() 
{ 
        throw new NotImplementedException(); 
}
با کمی دقت در تکه کد بالا می‌توان به این نتیجه رسید که جدا کردن روال محاسبه تخفیف یک طراحی و بازسازی خوب است. در سه خطی که مربوط به محاسبه تخفیف است یک متغیر محلی به نام discount مقداردهی شده است و یک متغیر محلی به نام price فقط خوانده شده‌است. این کد را می‌توان به صورت زیر بازسازی کرد: 
public void SetPayableAmount(dynamic orderItem)
{ 
        var price = orderItem.Price; 
        var discount = GetDiscount(price); 
        orderItem.PayableAmount = orderItem.Price - discount; 
} 
public dynamic GetDiscount(decimal price) 
{ 
        var discountPlan = GetDiscountPlan(); 
        var discountPercentage = discountPlan.Percentage; 
        return price * discountPercentage; 
} 
private dynamic GetDiscountPlan() 
{ 
       throw new NotImplementedException(); 
}
در این بازسازی، به دلیل نیاز کد استخراج شده به مقدار متغیر price، این متغیر را به صورت یک پارامتر، به متد جدید ایجاد شده، ارسال کردیم. همچین مقدار تخفیف محاسبه شده را نیز به دلیل نیاز به آن در متد بالادستی به صورت مقدار خروجی به آن متد بازگرداندیم.

ابزارهای کمکی برای این بازسازی کد 

در ابزارهای زیر امکاناتی برای انجام این بازسازی کد تعبیه شده است:
مایکروسافت ویژوال استودیو: میانبر Ctrl+R,M را بعد از انتخاب کد منتخب برای استخراج، استفاده نمایید. 
Jetbrains Resharper: این ابزار را می‌توان با میانبرهای مایکروسافت ویژوال استودیو استفاده کرد. امکانات کلی این ابزار از امکانات موجود در مایکروسافت ویژوال استودیو بیشتر است.