آموزش برنامه نویسی ریفکتورینگ

آموزش برنامه نویسی ریفکتورینگ

ریفکتورینگ در برنامه نویسی (بخش سوم)

 

آموزش برنامه نویسی ریفکتورینگ - بخش چهارم

در بخش های قبل آموزش ریفکتورینگ ما Refactoring را به شما معرفی کردیم. در بخش سوم آموزش فارسی Refactoring ما راجع به حذف متغیر play صحبت کردیک که در این قسمت به تست و اجرای آن می پردازیم.

 

چرا ریفکتورینگ؟

آموزش برنامه نویسی ریفکتورینگ - بخش چهارم

 

در بخش های قبل آموزش ریفکتورینگ ما Refactoring را به شما معرفی کردیم. در بخش سوم آموزش فارسی Refactoring ما راجع به حذف متغیر play صحبت کردیک که در این قسمت به تست و اجرای آن می پردازیم.

 

ریفکتورینگ در برنامه نویسی (بخش سوم)
 

کامپایل میکنیم-تست میکنیم و تایید میکنیم.

 با این فشردگی میتوانیم تابع Declaration را به amountFor برای حذف کردن پارامتر  play تغییر دهیم.  این کار را در دو مرحله انجام میدهیم.
ابتدا از یک تابع جدید به جای amountFor استفاده میکنیم.


function amountFor(aPerformance, play) {
let result = 0;switch (playFor(aPerformance).type) {
case "tragedy":
result = 40000;
if (aPerformance.audience > 30) {
result += 1000 * (aPerformance.audience 30)
;
}
break;
case "comedy":
result = 30000;
if (aPerformance.audience > 20) {
result += 10000 + 500 * (aPerformance.audience 20)
;
}
result += 300 * aPerformance.audience;
break;
default:
throw new Error(`unknown type: ${playFor(aPerformance).type}`);
}
return result;
}

 

اجرا میکنیم-تست میکنیم- تایید میکنیم و سپس پارامتر را پاک میکنیم.

 


function statement (invoice, plays) {
let totalAmount = 0;
let volumeCredits = 0;
let result = `Statement for ${invoice.customer}\n`;
const format = new Intl.NumberFormat("enUS",
{ style: "currency", currency: "USD",
minimumFractionDigits: 2 }).format;
for (let perf of invoice.performances) {
let thisAmount = amountFor(perf, playFor(perf));
// add volume credits
volumeCredits += Math.max(perf.audience 30,
0);
// add extra credit for every ten comedy attendees
if ("comedy" === playFor(perf).type) volumeCredits += Math.floor(perf.audience // print line for this order
result += ` ${playFor(perf).name}: ${format(thisAmount/100)} (${perf.audience} totalAmount += thisAmount;
}
result += `Amount owed is ${format(totalAmount/100)}\n`;
result += `You earned ${volumeCredits} credits\n`;
return result;

 


function amountFor(aPerformance, play) {
let result = 0;
switch (playFor(aPerformance).type) {
case "tragedy":
result = 40000;
if (aPerformance.audience > 30) {
result += 1000 * (aPerformance.audience 30)
;
}
break;
case "comedy":
result = 30000;
if (aPerformance.audience > 20) {
result += 10000 + 500 * (aPerformance.audience 20)
;
}
result += 300 * aPerformance.audience;
break;
default:
throw new Error(`unknown type: ${playFor(aPerformance).type}`);
}
return result;
}

 

و مجددا اجرا میکنیم-تست میکنیم- تایید میکنیم

این نوع ریفکتورینگ به  برخی برنامه نویسان هشدار میدهد.
 قبلا این کد برای جستجو کردن play یک بار در حلقه ی loop اجرا میشد؛اما اکنون، سه بار اجرا میشود. بعدا درباره ی عملکرد این ریفکتورینگ و کارایی آن صحبت خواهیم کرد،اما در این لحضه باید بگویم که همانطور که مشاهده میکنید بعید است که این تغییرات به طور قابل ملاحظه ای روی کارایی تاثیری داشته باشد، حتی اگر اینچنین هم باشد فقط یک فاکتور خیلی خوب برای بهبود عملکرد کد های پایه میباشد. 

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

 


function statement (invoice, plays) {
let totalAmount = 0;
let volumeCredits = 0;
let result = `Statement for ${invoice.customer}\n`;
const format = new Intl.NumberFormat("enUS",
{ style: "currency", currency: "USD",
minimumFractionDigits: 2 }).format;
for (let perf of invoice.performances) {
// add volume credits
volumeCredits += Math.max(perf.audience 30,
0);
// add extra credit for every ten comedy attendees
if ("comedy" === playFor(perf).type) volumeCredits += Math.floor(perf.audience // print line for this order
result += ` ${playFor(perf).name}: ${format(amountFor(perf)/100)} (${perf.audience} totalAmount += amountFor(perf);
}
result += `Amount owed is ${format(totalAmount/100)}\n`;
result += `You earned ${volumeCredits} credits\n`;
return result;

 

استخراج اعتبار حجم

وضعیت فعلی بدنه تابع statement اینجا است:


function statement (invoice, plays) {
let totalAmount = 0;
let volumeCredits = 0;
let result = `Statement for ${invoice.customer}\n`;
const format = new Intl.NumberFormat("enUS",
{ style: "currency", currency: "USD",
minimumFractionDigits: 2 }).format;
for (let perf of invoice.performances) {
// add volume credits
volumeCredits += Math.max(perf.audience 30,
0);
// add extra credit for every ten comedy attendees
if ("comedy" === playFor(perf).type) volumeCredits += Math.floor(perf.audience // print line for this order
result += ` ${playFor(perf).name}: ${format(amountFor(perf)/100)} (${perf.audience} totalAmount += amountFor(perf);
}
result += `Amount owed is ${format(totalAmount/100)}\n`;
result += `You earned ${volumeCredits} credits\n`;
return result;

 

حالا ما از حذف متغیر play لذت می بریم چون باعث می شود که محاسبه حجم اعتبار را با حذف یکی از متغیرهای محلی انجام دهیم.
هنوز با دو چیز دیگر سرو کار داریم. Perfبرای گذشتن آسان است، اما volumeCredits کمی پیچیده تر از آن است زیرا یک مخزن است که در هر بار اجرای حلقه بروز رسانی میشود.بهترین و پیشنهاد و شرط ما این است که آن مقدار را مانند یک سایه داخل تابع استخراج شده راه اندازی کنیم و آن مقدار را برگردانیم.


function volumeCreditsFor(perf) {
let volumeCredits = 0;
volumeCredits += Math.max(perf.audience 30,
0);
if ("comedy" === playFor(perf).type) volumeCredits += Math.floor(perf.audience return volumeCredits;
}

top level…

function statement (invoice, plays) {
let totalAmount = 0;
let volumeCredits = 0;
let result = `Statement for ${invoice.customer}\n`;
const format = new Intl.NumberFormat("enUS",
{ style: "currency", currency: "USD",
minimumFractionDigits: 2 }).format;
for (let perf of invoice.performances) {
volumeCredits += volumeCreditsFor(perf);
// print line for this order
result += ` ${playFor(perf).name}: ${format(amountFor(perf)/100)} (${perf.audience} totalAmount += amountFor(perf);
}
result += `Amount owed is ${format(totalAmount/100)}\n`;
result += `You earned ${volumeCredits} credits\n`;
return result;


تست، اجرا و تایید میکنیم و سپس متغیرهای داخل تابع جدید را تغییر نام میدهیم.

 


function volumeCreditsFor(aPerformance) {
let result = 0;
result += Math.max(aPerformance.audience 30,
0);
if ("comedy" === playFor(aPerformance).type) result += Math.floor(aPerformance.return result;
}

ما این را در یک مرحله نشان دادیم،اما همانطور که قبلا یکی را تغییر نام دادیم باید بعد از هر مرحله اجرا تست و تایید کنیم.
 

منبع مورد استفاده

refactoring.improving.the.design.of.existing.code.2nd.edition

در بخش های بعد "refactoring چیست" به موارد بیشتری خواهیم پرداخت. با تشکر - مجموعه ABLY

نظرات یا سوالات خودرا با ما درمیان بگذارید

0912 097 5516 :شماره تماس
0713 625 1757 :شماره تماس