الفرق بين المراجعتين لصفحة: «Refactoring/replace nested conditional with guard clauses»
Khaled-yassin (نقاش | مساهمات) أنشأ الصفحة ب'<noinclude>{{DISPLAYTITLE: تبديل الشرطيات المتداخلة بعبارات الحماية (Replace Nested Conditional with Guard Clauses}}</noinclude> ==...' |
جميل-بيلوني (نقاش | مساهمات) ط مراجعة وتدقيق |
||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE: تبديل الشرطيات المتداخلة بعبارات الحماية (Replace Nested Conditional with Guard Clauses}}</noinclude> | <noinclude>{{DISPLAYTITLE: تبديل الشرطيات المتداخلة بعبارات الحماية (Replace Nested Conditional with Guard Clauses}}</noinclude> | ||
== المشكلة == | == المشكلة == | ||
وجود مجموعة متداخلة من | وجود مجموعة متداخلة من الشروط وصعوبة تحديد التدفق الطبيعي لتنفيذ الشيفرة البرمجية. | ||
== الحل == | == الحل == | ||
عزل جميع الاختبارات الخاصة والحالات الطرفية في عبارات منفصلة ووضعها قبل الاختبارات الرئيسية. من الناحية المثالية، يجب أن يكون لديك قائمة "مسطحة" من | عزل جميع الاختبارات الخاصة والحالات الطرفية في عبارات منفصلة ووضعها قبل الاختبارات الرئيسية. من الناحية المثالية، يجب أن يكون لديك قائمة "مسطحة" من الشروط، واحدةً تلو الأخرى. | ||
=== | == مثال == | ||
=== قبل إعادة التصميم === | |||
يوجد لدينا الدالة <code>()getPayAmount</code> التي تتحقق من القيمة المُستدعاة معها عبر عدد من الشروط المتشعبة - مع استعمال المتغير <code>result</code> للحصول على النتيجة وإعادتها في النهاية - مما يجعل معرفة تدفق ومسار الدالة أمرًا معقدًا: | |||
في لغة Java:<syntaxhighlight lang="java"> | في لغة Java:<syntaxhighlight lang="java"> | ||
public double getPayAmount() { | public double getPayAmount() { | ||
سطر 91: | سطر 93: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== بعد إعادة التصميم === | |||
حذف المتغير <code>result</code> وجعل الشروط المراد التحقق منها في مستوًى واحد ضمن الدالة <code>()getPayAmount</code>: | |||
في لغة Java:<syntaxhighlight lang="java"> | في لغة Java:<syntaxhighlight lang="java"> | ||
public double getPayAmount() { | public double getPayAmount() { | ||
سطر 144: | سطر 148: | ||
== لم إعادة التصميم؟ == | == لم إعادة التصميم؟ == | ||
من السهل إلى حد ما اكتشاف " | من السهل إلى حد ما اكتشاف "الشروط المُّعقدة". وكلما ازدادت المسافات البادئة في كل مستوى من التداخلية التي تتجه إلى اليمين في الشيفرة، ازداد بقدرها الألم والشقاء:<syntaxhighlight lang="java"> | ||
if () { | if () { | ||
if () { | if () { | ||
سطر 165: | سطر 169: | ||
} | } | ||
} | } | ||
</syntaxhighlight>ومن الصعب معرفة ما | </syntaxhighlight>ومن الصعب معرفة ما يفعله كل شرط وكيف يتم التحقق منه، إذ لا يكون التدفق "العادي" لتنفيذ الشيفرة البرمجية واضحًا وضوح الشمس. وتشير مثل هذه الشروط إلى التطور المتسارع مع إضافة كل شرط كإجراء مؤقت دون أي عناء في التفكير في تحسين الهيكل العام. | ||
لتبسيط الموقف، | لتبسيط الموقف، تُعزَل الحالات الخاصة إلى شروط منفصلة تُنهِي التنفيذ مباشرةً ثم تُعيد قيمةً فارغةً إذا كانت عبارات الحماية صحيحة. في الواقع، مهمتك هنا هي جعل الهيكل مسطحُا. | ||
== آلية الحل == | == آلية الحل == | ||
حاول تخليص الشيفرة البرمجية من الآثار الجانبية؛ قد يكون [[Refactoring/separate query from modifier|فصل الاستعلام عن المُعدِّل]] مفيدًا لهذا الغرض. سيكون هذا الحل ضروريًا لإجراء إعادة التشكيل المبينة أدناه. | |||
# اعزل جميع عبارات الحماية التي تؤدي إلى استدعاء استثناء أو إلى الإعادة الفورية لقيمة من التابع. وضع هذه الشروط في بداية التابع. | # اعزل جميع عبارات الحماية التي تؤدي إلى استدعاء استثناء أو إلى الإعادة الفورية لقيمة من التابع. وضع هذه الشروط في بداية التابع. | ||
# بعد اكتمال إعادة الترتيب وإكمال كافة الاختبارات بنجاح، راجع ما إذا كان يمكنك استخدام [[Refactoring/consolidate conditional expression|توحيد التعبير الشرطي]] لعبارات الحماية التي تؤدي إلى نفس الاستثناءات أو القيم المُعادة. | # بعد اكتمال إعادة الترتيب وإكمال كافة الاختبارات بنجاح، راجع ما إذا كان يمكنك استخدام [[Refactoring/consolidate conditional expression|توحيد التعبير الشرطي]] لعبارات الحماية التي تؤدي إلى نفس الاستثناءات أو القيم المُعادة. |
المراجعة الحالية بتاريخ 08:41، 19 ديسمبر 2018
المشكلة
وجود مجموعة متداخلة من الشروط وصعوبة تحديد التدفق الطبيعي لتنفيذ الشيفرة البرمجية.
الحل
عزل جميع الاختبارات الخاصة والحالات الطرفية في عبارات منفصلة ووضعها قبل الاختبارات الرئيسية. من الناحية المثالية، يجب أن يكون لديك قائمة "مسطحة" من الشروط، واحدةً تلو الأخرى.
مثال
قبل إعادة التصميم
يوجد لدينا الدالة ()getPayAmount
التي تتحقق من القيمة المُستدعاة معها عبر عدد من الشروط المتشعبة - مع استعمال المتغير result
للحصول على النتيجة وإعادتها في النهاية - مما يجعل معرفة تدفق ومسار الدالة أمرًا معقدًا:
في لغة Java:
public double getPayAmount() {
double result;
if (isDead){
result = deadAmount();
}
else {
if (isSeparated){
result = separatedAmount();
}
else {
if (isRetired){
result = retiredAmount();
}
else{
result = normalPayAmount();
}
}
}
return result;
}
في لغة C#:
public double GetPayAmount()
{
double result;
if (isDead)
{
result = DeadAmount();
}
else
{
if (isSeparated)
{
result = SeparatedAmount();
}
else
{
if (isRetired)
{
result = RetiredAmount();
}
else
{
result = NormalPayAmount();
}
}
}
return result;
}
في لغة PHP:
public function getPayAmount() {
if ($this->isDead)
$result = $this->deadAmount();
else {
if ($this->isSeparated)
$result = $this->separatedAmount();
else {
if ($this->isRetired)
$result = $this->retiredAmount();
else
$result = $this->normalPayAmount();
}
}
return $result;
}
في لغة Python:
def getPayAmount(self):
if self.isDead:
result = deadAmount()
else:
if self.isSeparated:
result = separatedAmount()
else:
if self.isRetired:
result = retiredAmount()
else:
result = normalPayAmount()
return result
بعد إعادة التصميم
حذف المتغير result
وجعل الشروط المراد التحقق منها في مستوًى واحد ضمن الدالة ()getPayAmount
:
في لغة Java:
public double getPayAmount() {
if (isDead){
return deadAmount();
}
if (isSeparated){
return separatedAmount();
}
if (isRetired){
return retiredAmount();
}
return normalPayAmount();
}
في لغة C#:
public double GetPayAmount()
{
if (isDead)
{
return DeadAmount();
}
if (isSeparated)
{
return SeparatedAmount();
}
if (isRetired)
{
return RetiredAmount();
}
return NormalPayAmount();
}
في لغة PHP:
public function getPayAmount() {
if ($this->isDead)
return $this->deadAmount();
if ($this->isSeparated)
return $this->separatedAmount();
if ($this->isRetired)
return $this->retiredAmount();
return $this->normalPayAmount();
}
في لغة Python:
def getPayAmount(self):
if self.isDead:
return deadAmount()
if self.isSeparated:
return separatedAmount()
if self.isRetired:
return retiredAmount()
return normalPayAmount()
لم إعادة التصميم؟
من السهل إلى حد ما اكتشاف "الشروط المُّعقدة". وكلما ازدادت المسافات البادئة في كل مستوى من التداخلية التي تتجه إلى اليمين في الشيفرة، ازداد بقدرها الألم والشقاء:
if () {
if () {
do {
if () {
if () {
if () {
...
}
}
...
}
...
}
while ();
...
}
else {
...
}
}
ومن الصعب معرفة ما يفعله كل شرط وكيف يتم التحقق منه، إذ لا يكون التدفق "العادي" لتنفيذ الشيفرة البرمجية واضحًا وضوح الشمس. وتشير مثل هذه الشروط إلى التطور المتسارع مع إضافة كل شرط كإجراء مؤقت دون أي عناء في التفكير في تحسين الهيكل العام.
لتبسيط الموقف، تُعزَل الحالات الخاصة إلى شروط منفصلة تُنهِي التنفيذ مباشرةً ثم تُعيد قيمةً فارغةً إذا كانت عبارات الحماية صحيحة. في الواقع، مهمتك هنا هي جعل الهيكل مسطحُا.
آلية الحل
حاول تخليص الشيفرة البرمجية من الآثار الجانبية؛ قد يكون فصل الاستعلام عن المُعدِّل مفيدًا لهذا الغرض. سيكون هذا الحل ضروريًا لإجراء إعادة التشكيل المبينة أدناه.
- اعزل جميع عبارات الحماية التي تؤدي إلى استدعاء استثناء أو إلى الإعادة الفورية لقيمة من التابع. وضع هذه الشروط في بداية التابع.
- بعد اكتمال إعادة الترتيب وإكمال كافة الاختبارات بنجاح، راجع ما إذا كان يمكنك استخدام توحيد التعبير الشرطي لعبارات الحماية التي تؤدي إلى نفس الاستثناءات أو القيم المُعادة.