الفرق بين المراجعتين ل"Refactoring/remove assignments to parameters"

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث
(إنشاء الصفحة. هذه الصفحة من مساهمات "نور تامر".)
 
ط (مراجعة وتدقيق.)
 
سطر 9: سطر 9:
  
 
==== قبل إعادة التصميم ====
 
==== قبل إعادة التصميم ====
نلاحظ وجود عمليّة إسنادٍ (من بعد الإنقاص بمقدار 2) إلى معامل التابع الوارد باسم <code>inputVal</code>:<syntaxhighlight lang="java">
+
نلاحظ وجود عمليّة إسنادٍ (من بعد الإنقاص بمقدار 2) إلى معامل التابع الوارد باسم <code>inputVal</code>:
 +
 
 +
في لغة Java:<syntaxhighlight lang="java">
 
int discount(int inputVal, int quantity) {
 
int discount(int inputVal, int quantity) {
 
   if (inputVal > 50) {
 
   if (inputVal > 50) {
سطر 17: سطر 19:
 
}
 
}
  
 +
</syntaxhighlight>في لغة #C:<syntaxhighlight lang="c#">
 +
int Discount(int inputVal, int quantity)
 +
{
 +
  if (inputVal > 50)
 +
  {
 +
    inputVal -= 2;
 +
  }
 +
  // ...
 +
}
 +
</syntaxhighlight>في لغة PHP:<syntaxhighlight lang="php">
 +
function discount($inputVal, $quantity) {
 +
  if ($inputVal > 50) {
 +
    $inputVal -= 2;
 +
  }
 +
  ...
 +
</syntaxhighlight>في لغة Python:<syntaxhighlight lang="python">
 +
def discount(inputVal, quantity):
 +
    if inputVal > 50:
 +
        inputVal -= 2
 +
    # ...
 +
</syntaxhighlight>في لغة TypeScript:<syntaxhighlight lang="typescript">
 +
discount(inputVal: number, quantity: number): number {
 +
  if (inputVal > 50) {
 +
    inputVal -= 2;
 +
  }
 +
  // ...
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
==== بعد إعادة التصميم ====
 +
يُعرَّف متغيِّرٌ محليٌّ جديدٌ باسم <code>result</code>، وتُسنَد إليه قيمة المعامل المطلوب (وهو <code>inputVal</code>) واستخدام المتغيِّر الجديد عوضًا عنه:
  
==== بعد إعادة التصميم ====
+
في لغة Java:<syntaxhighlight lang="java">
يُعرَّف متغيِّرٌ محليٌّ جديدٌ باسم <code>result</code>، وتُسنَد إليه قيمة المعامل المطلوب (وهو <code>inputVal</code>) واستخدام المتغيِّر الجديد عوضًا عنه:<syntaxhighlight lang="java">
 
 
int discount(int inputVal, int quantity) {
 
int discount(int inputVal, int quantity) {
 
   int result = inputVal;
 
   int result = inputVal;
سطر 29: سطر 59:
 
}
 
}
  
 +
</syntaxhighlight>في لغة #C:<syntaxhighlight lang="c#">
 +
int Discount(int inputVal, int quantity)
 +
{
 +
  int result = inputVal;
 +
 
 +
  if (inputVal > 50)
 +
  {
 +
    result -= 2;
 +
  }
 +
  // ...
 +
}
 +
</syntaxhighlight>في لغة PHP:<syntaxhighlight lang="php">
 +
function discount($inputVal, $quantity) {
 +
  $result = $inputVal;
 +
  if ($inputVal > 50) {
 +
    $result -= 2;
 +
  }
 +
  ...
 +
</syntaxhighlight>في لغة Python:<syntaxhighlight lang="python">
 +
def discount(inputVal, quantity):
 +
    result = inputVal
 +
    if inputVal > 50:
 +
        result -= 2
 +
    # ...
 +
</syntaxhighlight>في لغة TypeScript:<syntaxhighlight lang="typescript">
 +
discount(inputVal: number, quantity: number): number {
 +
  let result = inputVal;
 +
  if (inputVal > 50) {
 +
    result -= 2;
 +
  }
 +
  // ...
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 
 
== لم إعادة التصميم؟ ==
 
== لم إعادة التصميم؟ ==
إنّ الهدف من إعادة التصميم بمثل هذه الحالة هو السبب ذاته وراء تجزئة المتغيِّر المؤقَّت (split temporary variable) والفرق بينهما هو التعامل مع المعاملات (parameters) هنا ومع المتغيِّرات المحليّة (variables) هناك، ويتلخَّص الهدف من إعادة التصميم بنقطتين:
+
إنّ الهدف من إعادة التصميم بمثل هذه الحالة هو السبب ذاته وراء [[Refactoring/split temporary variable|تجزئة المتغيِّر المؤقَّت]] (split temporary variable) والفرق بينهما هو التعامل مع المعاملات (parameters) هنا ومع المتغيِّرات المحليّة (variables) هناك، ويتلخَّص الهدف من إعادة التصميم بنقطتين:
 
* أولًا؛ إن مُرِّر المعامل عبر مرجعيّته (reference) فستُمرَّر قيمةُ المعامل (بعد تغييرها داخل التابع [method]) إلى المتغيِّر الوسيط (argument) الذي استدعى التابع، وغالبًا ما يحدث هذا دون قصدٍ ويسبِّب بعض الآثار الجانبيّة غير المرغوبة، أمّا إن كان تمرير المعامل -بلغة البرمجة المُستخدَمة- تمريرًا بالقيمة (pass by value) لا بالمرجعيّة فإنّ هذا سيُتعِب المبرمجين غير المعتادين على ذلك.
 
* أولًا؛ إن مُرِّر المعامل عبر مرجعيّته (reference) فستُمرَّر قيمةُ المعامل (بعد تغييرها داخل التابع [method]) إلى المتغيِّر الوسيط (argument) الذي استدعى التابع، وغالبًا ما يحدث هذا دون قصدٍ ويسبِّب بعض الآثار الجانبيّة غير المرغوبة، أمّا إن كان تمرير المعامل -بلغة البرمجة المُستخدَمة- تمريرًا بالقيمة (pass by value) لا بالمرجعيّة فإنّ هذا سيُتعِب المبرمجين غير المعتادين على ذلك.
 
* ثانيًا؛ سيصبحُ من الصعب (بوجود الإسناداتُ المتعدِّدة وبقيمٍ مختلفةٍ إلى نفس المعامل) تحديدُ البيانات المُخزَّنة في المعامل عند نقطةٍ زمنيّةٍ مُحدَّدة، وتزداد هذه المشكلة سوءًا إن وُثِّق المعامل ومحتوياته مع اختلاف القيم الفعليّة عمّا هو متوقعٌ وجودُه في التابع.
 
* ثانيًا؛ سيصبحُ من الصعب (بوجود الإسناداتُ المتعدِّدة وبقيمٍ مختلفةٍ إلى نفس المعامل) تحديدُ البيانات المُخزَّنة في المعامل عند نقطةٍ زمنيّةٍ مُحدَّدة، وتزداد هذه المشكلة سوءًا إن وُثِّق المعامل ومحتوياته مع اختلاف القيم الفعليّة عمّا هو متوقعٌ وجودُه في التابع.
سطر 38: سطر 99:
 
== فوائد تطبيق الحل ==
 
== فوائد تطبيق الحل ==
 
* سيصبح كلُّ جزءٍ من شيفرة البرنامج مسؤولًا عن مهمةٍ واحدةٍ ممّا يجعل من السهل صيانة (maintain) البرنامج، إذ من الممكن إجراء أيّ تبديلٍ دون القلق حيال الآثار الجانبية التي قد تنجم عن هذا التبديل.
 
* سيصبح كلُّ جزءٍ من شيفرة البرنامج مسؤولًا عن مهمةٍ واحدةٍ ممّا يجعل من السهل صيانة (maintain) البرنامج، إذ من الممكن إجراء أيّ تبديلٍ دون القلق حيال الآثار الجانبية التي قد تنجم عن هذا التبديل.
* سيساعد على استخراج الشيفرات المتكرِّرة إلى توابع مستقلِّة.
+
* سيساعد على [[Refactoring/extract method|استخراج الشيفرات المتكرِّرة إلى توابع مستقلِّة]].
  
 
== آلية الحل ==
 
== آلية الحل ==
سطر 50: سطر 111:
 
== مصادر ==
 
== مصادر ==
 
* [https://refactoring.guru/remove-assignments-to-parameters صفحة توثيق إزالة الإسناد إلى المعاملات في موقع refactoring.guru.]
 
* [https://refactoring.guru/remove-assignments-to-parameters صفحة توثيق إزالة الإسناد إلى المعاملات في موقع refactoring.guru.]
[[تصنيف: Refactoring]]
+
[[تصنيف:Refactoring]]
 +
[[تصنيف:Refactoring Techniques]]
 +
[[تصنيف:Refactoring Composing Methods]]

المراجعة الحالية بتاريخ 08:22، 2 مارس 2019

المشكلة

إسناد قيمةٍ ما إلى أحد المعاملات (parameter) داخل التابع (method body).

الحل

استخدام متغيِّرٍ محليٍّ (local variable) بدلًا من المعامل.

مثال

قبل إعادة التصميم

نلاحظ وجود عمليّة إسنادٍ (من بعد الإنقاص بمقدار 2) إلى معامل التابع الوارد باسم inputVal:

في لغة Java:

int discount(int inputVal, int quantity) {
  if (inputVal > 50) {
    inputVal -= 2;
  }
  //...
}

في لغة #C:

int Discount(int inputVal, int quantity) 
{
  if (inputVal > 50) 
  {
    inputVal -= 2;
  }
  // ...
}

في لغة PHP:

function discount($inputVal, $quantity) {
  if ($inputVal > 50) {
    $inputVal -= 2;
  }
  ...

في لغة Python:

def discount(inputVal, quantity):
    if inputVal > 50:
        inputVal -= 2
    # ...

في لغة TypeScript:

discount(inputVal: number, quantity: number): number {
  if (inputVal > 50) {
    inputVal -= 2;
  }
  // ...
}

بعد إعادة التصميم

يُعرَّف متغيِّرٌ محليٌّ جديدٌ باسم result، وتُسنَد إليه قيمة المعامل المطلوب (وهو inputVal) واستخدام المتغيِّر الجديد عوضًا عنه:

في لغة Java:

int discount(int inputVal, int quantity) {
  int result = inputVal;
  if (inputVal > 50) {
    result -= 2;
  }
  //...
}

في لغة #C:

int Discount(int inputVal, int quantity) 
{
  int result = inputVal;
  
  if (inputVal > 50) 
  {
    result -= 2;
  }
  // ...
}

في لغة PHP:

function discount($inputVal, $quantity) {
  $result = $inputVal;
  if ($inputVal > 50) {
    $result -= 2;
  }
  ...

في لغة Python:

def discount(inputVal, quantity):
    result = inputVal
    if inputVal > 50:
        result -= 2
    # ...

في لغة TypeScript:

discount(inputVal: number, quantity: number): number {
  let result = inputVal;
  if (inputVal > 50) {
    result -= 2;
  }
  // ...
}

لم إعادة التصميم؟

إنّ الهدف من إعادة التصميم بمثل هذه الحالة هو السبب ذاته وراء تجزئة المتغيِّر المؤقَّت (split temporary variable) والفرق بينهما هو التعامل مع المعاملات (parameters) هنا ومع المتغيِّرات المحليّة (variables) هناك، ويتلخَّص الهدف من إعادة التصميم بنقطتين:

  • أولًا؛ إن مُرِّر المعامل عبر مرجعيّته (reference) فستُمرَّر قيمةُ المعامل (بعد تغييرها داخل التابع [method]) إلى المتغيِّر الوسيط (argument) الذي استدعى التابع، وغالبًا ما يحدث هذا دون قصدٍ ويسبِّب بعض الآثار الجانبيّة غير المرغوبة، أمّا إن كان تمرير المعامل -بلغة البرمجة المُستخدَمة- تمريرًا بالقيمة (pass by value) لا بالمرجعيّة فإنّ هذا سيُتعِب المبرمجين غير المعتادين على ذلك.
  • ثانيًا؛ سيصبحُ من الصعب (بوجود الإسناداتُ المتعدِّدة وبقيمٍ مختلفةٍ إلى نفس المعامل) تحديدُ البيانات المُخزَّنة في المعامل عند نقطةٍ زمنيّةٍ مُحدَّدة، وتزداد هذه المشكلة سوءًا إن وُثِّق المعامل ومحتوياته مع اختلاف القيم الفعليّة عمّا هو متوقعٌ وجودُه في التابع.

فوائد تطبيق الحل

  • سيصبح كلُّ جزءٍ من شيفرة البرنامج مسؤولًا عن مهمةٍ واحدةٍ ممّا يجعل من السهل صيانة (maintain) البرنامج، إذ من الممكن إجراء أيّ تبديلٍ دون القلق حيال الآثار الجانبية التي قد تنجم عن هذا التبديل.
  • سيساعد على استخراج الشيفرات المتكرِّرة إلى توابع مستقلِّة.

آلية الحل

  1. إنشاء متغيِّرٍ محليٍّ (local vaiable) وإسناد قيمة المعامل الأوليّة (initial value) إليه.
  2. تبديل المعامل إلى المتغيِّر الجديد بأيِّ شيفرةٍ ترِد بعد تعليمة التصريح عنه (بالخطوة السابقة).

انظر أيضًا

مصادر