الفرق بين المراجعتين ل"Refactoring/introduce null object"

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث
(أنشأ الصفحة ب'<noinclude>{{DISPLAYTITLE: تقديم الكائن الفارغ Introduce Null Object}}</noinclude> == المشكلة == تؤدي إعادة بعض التوابع للق...')
 
ط (مراجعة وتدقيق.)
 
سطر 1: سطر 1:
<noinclude>{{DISPLAYTITLE: تقديم الكائن الفارغ Introduce Null Object}}</noinclude>
+
<noinclude>{{DISPLAYTITLE: تقديم الكائن الفارغ (Introduce Null Object)}}</noinclude>
 
== المشكلة ==
 
== المشكلة ==
تؤدي إعادة بعض التوابع للقيمة <code>null</code> بدلًا من الكائنات الحقيقية، لامتلاء الشيفرة البرمجية بالعديد من نقاط التحقق من القيمة <code>null</code>.
+
تؤدي إعادة بعض التوابع للقيمة <code>null</code> بدلًا من الكائنات الحقيقية إلى امتلاء الشيفرة البرمجية بالعديد من نقاط التحقق من القيمة <code>null</code>.
  
 
== الحل ==
 
== الحل ==
سطر 9: سطر 9:
  
 
==== قبل إعادة التصميم ====
 
==== قبل إعادة التصميم ====
 +
وجودة نقطة تحقق شرطية من الكائن <code>customer</code> لاتخاذ إجراء مناسب إن كانت قيمته <code>null</code>:
 +
 
في لغة Java:<syntaxhighlight lang="java">
 
في لغة Java:<syntaxhighlight lang="java">
 
if (customer == null) {
 
if (customer == null) {
سطر 38: سطر 40:
  
 
==== بعد إعادة التصميم ====
 
==== بعد إعادة التصميم ====
 +
إنشاء صنف عدمي للكائن <code>customer</code> يدعى <code>NullCustomer</code> يستبدل القيم العدمية فيه:
 +
 
في لغة Java:<syntaxhighlight lang="java">
 
في لغة Java:<syntaxhighlight lang="java">
 
class NullCustomer extends Customer {
 
class NullCustomer extends Customer {
سطر 117: سطر 121:
  
 
== آلية الحل ==
 
== آلية الحل ==
# أنشئ صنف فرعي للصنف المعني يقوم بدور كائن فارغ.
+
# أنشئ صنفًا فرعيًّا للصنف المعني يقوم بدور كائن فارغ.
 
# في كلا الصنفين، أنشئ التابع <code>isNull()‎</code> الذي يعيد <code>true</code> لكائن فارغ و <code>false</code> للصنف الحقيقي.
 
# في كلا الصنفين، أنشئ التابع <code>isNull()‎</code> الذي يعيد <code>true</code> لكائن فارغ و <code>false</code> للصنف الحقيقي.
# ابحث عن جميع الأماكن التي يمكن أن تُعيد فيها <code>null</code> للشيفرة بدلًا من كائنٍ حقيقيٍ. وغيَّر الشيفرة البرمجية بحيث تُعيد كائنًا فارغًا.
+
# ابحث عن جميع الأماكن التي يمكن أن تُعيد فيها <code>null</code> للشيفرة بدلًا من كائنٍ حقيقيٍ، وغيَّر الشيفرة البرمجية بحيث تُعيد كائنًا فارغًا.
# ابحث عن جميع الأماكن حيث تُقارن متغيرات الصنف الحقيقي مع <code>null</code>. واستبدال نقاط التحقق هذه باستدعاءات للتابع<code>isNull()‎.</code>
+
# ابحث عن جميع الأماكن حيث تُقارن متغيرات الصنف الحقيقي مع <code>null</code>، واستبدل نقاط التحقق هذه باستدعاءات للتابع <code>isNull()‎.</code>
#* إذا نُفذت توابع الصنف الأصلي داخل هذه الشرطيات عندما لا تساوي قيمة ما <code>null</code>، أعِد تعريف هذه التوابع في الصنف الفارغ وادرج فيه الشيفرة البرمجية من الجزء <code>else</code> من الشرط. ثم يمكنك حذف كامل الشرطية وتنفيذ تغيير السلوك عبر التعددية الشكلية.
+
#* إذا نُفّذَت توابع الصنف الأصلي داخل هذه الكتل الشرطية عندما لا تساوي قيمة ما <code>null</code>، أعِد تعريف هذه التوابع في الصنف الفارغ وأدرج فيه الشيفرة البرمجية من الجزء <code>else</code> من الشرط. ثم يمكنك حذف كامل الشرط وتنفيذ تغيير السلوك عبر التعددية الشكلية.
#* إذا لم تكن الأمور بهذه البساطة ولا يمكن إعادة تعريف التوابع، تحقق من إذا كان يمكنك ببساطة استخراج العوامل التي كان من المفترض تنفيذها في حالة القيمة <code>null</code> إلى توابع جديدة للكائن الفارغ. واستدعِ هذه التوابع بدلًا من الشيفرة البرمجية القديمة في <code>else</code> كعمليات افتراضية.
+
#* إذا لم تكن الأمور بهذه البساطة ولا يمكن إعادة تعريف التوابع، فتحقق من إذا كان يمكنك ببساطة استخراج العوامل التي كان من المفترض تنفيذها في حالة القيمة <code>null</code> إلى توابع جديدة للكائن الفارغ. واستدعِ هذه التوابع بدلًا من الشيفرة البرمجية القديمة في <code>else</code> كعمليات افتراضية.
  
 
== انظر أيضًا ==
 
== انظر أيضًا ==

المراجعة الحالية بتاريخ 13:09، 25 فبراير 2019

المشكلة

تؤدي إعادة بعض التوابع للقيمة null بدلًا من الكائنات الحقيقية إلى امتلاء الشيفرة البرمجية بالعديد من نقاط التحقق من القيمة null.

الحل

إعادة كائن فارغ يظهر السلوك الافتراضي بدلًا من null.

مثال

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

وجودة نقطة تحقق شرطية من الكائن customer لاتخاذ إجراء مناسب إن كانت قيمته null:

في لغة Java:

if (customer == null) {
  plan = BillingPlan.basic();
}
else {
  plan = customer.getPlan();
}

في لغة C#‎:

if (customer == null) 
{
  plan = BillingPlan.Basic();
}
else 
{
  plan = customer.GetPlan();
}

في لغة PHP:

if ($customer == null)
  $plan = BillingPlan::basic();
else
  $plan = $customer->getPlan();

في لغة Python:

if customer == None:
    plan = BillingPlan.basic()
else:
    plan = customer.getPlan()

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

إنشاء صنف عدمي للكائن customer يدعى NullCustomer يستبدل القيم العدمية فيه:

في لغة Java:

class NullCustomer extends Customer {
  boolean isNull() {
    return true;
  }
  Plan getPlan() {
    return new NullPlan();
  }
  // بعض وظائف NULL الأخرى.
}

// استبدل القيم الفارغة بالكائن Null.
customer = (order.customer != null) ?
  order.customer : new NullCustomer();

// استخدام كائن Null كما لو كان صنف فرعي عادي.
plan = customer.getPlan();

في لغة C#‎:

public sealed class NullCustomer: Customer 
{
  public override bool IsNull 
  {
    get { return true; }
  }
  
  public override Plan GetPlan() 
  {
    return new NullPlan();
  }
  // بعض وظائف NULL الأخرى.
}

// استبدل القيم الفارغة بالكائن Null.
customer = order.customer ?? new NullCustomer();

// استخدام كائن Null كما لو كان صنف فرعي عادي.
plan = customer.GetPlan();

في لغة PHP:

class NullCustomer extends Customer {
  function isNull() {
    return true;
  }
  function getPlan() {
    return new NullPlan();
  }
  // بعض وظائف NULL الأخرى.

// استبدل القيم الفارغة بالكائن Null.
$customer = ($order->customer != null) ?
  $order->customer :
  new NullCustomer();

// استخدام كائن Null كما لو كان صنف فرعي عادي.
$plan = $customer->getPlan();

في لغة Python:

class NullCustomer(Customer):

    def isNull(self):
        return True
    
    def getPlan(self):
        return self.NullPlan()
        
    # بعض وظائف NULL الأخرى.

# استبدل القيم الفارغة بالكائن Null.
customer = order.customer if order.customer != None else NullCustomer()

# استخدام كائن Null كما لو كان صنف فرعي عادي.
plan = customer.getPlan()

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

تُحيل العشرات من نقاط التحقق من القيمة null الشيفرةَ البرمجية أطول وأقبح.

مساوئ تطبيق الحل

  • يجب إنشاء صنف جديد آخر للتخلص من الشرطيات.

آلية الحل

  1. أنشئ صنفًا فرعيًّا للصنف المعني يقوم بدور كائن فارغ.
  2. في كلا الصنفين، أنشئ التابع isNull()‎ الذي يعيد true لكائن فارغ و false للصنف الحقيقي.
  3. ابحث عن جميع الأماكن التي يمكن أن تُعيد فيها null للشيفرة بدلًا من كائنٍ حقيقيٍ، وغيَّر الشيفرة البرمجية بحيث تُعيد كائنًا فارغًا.
  4. ابحث عن جميع الأماكن حيث تُقارن متغيرات الصنف الحقيقي مع null، واستبدل نقاط التحقق هذه باستدعاءات للتابع isNull()‎.
    • إذا نُفّذَت توابع الصنف الأصلي داخل هذه الكتل الشرطية عندما لا تساوي قيمة ما null، أعِد تعريف هذه التوابع في الصنف الفارغ وأدرج فيه الشيفرة البرمجية من الجزء else من الشرط. ثم يمكنك حذف كامل الشرط وتنفيذ تغيير السلوك عبر التعددية الشكلية.
    • إذا لم تكن الأمور بهذه البساطة ولا يمكن إعادة تعريف التوابع، فتحقق من إذا كان يمكنك ببساطة استخراج العوامل التي كان من المفترض تنفيذها في حالة القيمة null إلى توابع جديدة للكائن الفارغ. واستدعِ هذه التوابع بدلًا من الشيفرة البرمجية القديمة في else كعمليات افتراضية.

انظر أيضًا

مصادر