الفرق بين المراجعتين ل"Refactoring/replace constructor with factory method"

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث
ط (مراجعة وتدقيق.)
 
سطر 1: سطر 1:
 
<noinclude>{{DISPLAYTITLE: استبدال المُنشئ بتابع التصميم (Replace Constructor with Factory Method)}}</noinclude>  
 
<noinclude>{{DISPLAYTITLE: استبدال المُنشئ بتابع التصميم (Replace Constructor with Factory Method)}}</noinclude>  
 
= المشكلة =
 
= المشكلة =
لديك مُنشئ معقد يقوم بما هو أكثر من مجرد وضع قيم المعامل في حقول الكائن.
+
لديك مُنشئ (constructor) معقد يقوم بما هو أكثر من مجرد وضع قيم المعامل في حقول الكائن.
  
 
= الحل =
 
= الحل =
سطر 9: سطر 9:
  
 
==== قبل إعادة التصميم ====
 
==== قبل إعادة التصميم ====
في لغة Java:<syntaxhighlight lang="java">
+
وجود منشئ معقد للصنف <code>Employee</code>:
 +
 
 +
في لغة [[Java]]:<syntaxhighlight lang="java">
 
class Employee {
 
class Employee {
 
   Employee(int type) {
 
   Employee(int type) {
سطر 16: سطر 18:
 
   //...
 
   //...
 
}
 
}
</syntaxhighlight>في لغة C#‎:<syntaxhighlight lang="c#">
+
</syntaxhighlight>في لغة [[C#‎]]:<syntaxhighlight lang="c#">
 
public class Employee  
 
public class Employee  
 
{
 
{
سطر 25: سطر 27:
 
   //...
 
   //...
 
}
 
}
</syntaxhighlight>في لغة PHP:<syntaxhighlight lang="php">
+
</syntaxhighlight>في لغة [[PHP]]:<syntaxhighlight lang="php">
 
class Employee {
 
class Employee {
 
   // ...
 
   // ...
سطر 34: سطر 36:
 
}
 
}
  
 +
</syntaxhighlight>في لغة [[TypeScript]]:<syntaxhighlight lang="typescript">
 +
class Employee {
 +
  constructor(type: number) {
 +
    this.type = type;
 +
  }
 +
  //...
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
==== بعد إعادة التصميم ====
 
==== بعد إعادة التصميم ====
في لغة Java:<syntaxhighlight lang="java">
+
إنشاء تابع تصميم واستبداله بالمنشئ:
 +
 
 +
في لغة [[Java]]:<syntaxhighlight lang="java">
 
class Employee {
 
class Employee {
 
   static Employee create(int type) {
 
   static Employee create(int type) {
 
     employee = new Employee(type);
 
     employee = new Employee(type);
     // do some heavy lifting.
+
     // نفذ بعض الأمور المعقدة والضخمة هنا
 
     return employee;
 
     return employee;
 
   }
 
   }
 
   //...
 
   //...
 
}
 
}
</syntaxhighlight>في لغة C#‎:<syntaxhighlight lang="c#">
+
</syntaxhighlight>في لغة [[C#]]‎:<syntaxhighlight lang="c#">
 
public class Employee
 
public class Employee
 
{
 
{
سطر 52: سطر 63:
 
   {
 
   {
 
     employee = new Employee(type);
 
     employee = new Employee(type);
     // do some heavy lifting.
+
     // نفذ بعض الأمور المعقدة والضخمة هنا
 
     return employee;
 
     return employee;
 
   }
 
   }
 
   //...
 
   //...
 
}
 
}
</syntaxhighlight>في لغة PHP:<syntaxhighlight lang="php">
+
</syntaxhighlight>في لغة [[PHP]]:<syntaxhighlight lang="php">
 
class Employee {
 
class Employee {
 
   // ...
 
   // ...
 
   static public function create($type) {
 
   static public function create($type) {
 
     $employee = new Employee($type);
 
     $employee = new Employee($type);
     // do some heavy lifting.
+
     // نفذ بعض الأمور المعقدة والضخمة هنا
 
     return $employee;
 
     return $employee;
 
   }
 
   }
 
   // ...
 
   // ...
 +
}
 +
</syntaxhighlight>في لغة [[TypeScript]]:<syntaxhighlight lang="typescript">
 +
class Employee {
 +
  static create(type: number): Employee {
 +
    let employee = new Employee(type);
 +
    // نفذ بعض الأمور المعقدة والضخمة هنا
 +
    return employee;
 +
  }
 +
  //...
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
سطر 72: سطر 92:
 
يرتبط السبب الأكثر وضوحًا لاستخدام تقنية إعادة التصميم هذه [[Refactoring/replace type code with subclasses|باستبدال شيفرة النوع بالأصناف الفرعية]].
 
يرتبط السبب الأكثر وضوحًا لاستخدام تقنية إعادة التصميم هذه [[Refactoring/replace type code with subclasses|باستبدال شيفرة النوع بالأصناف الفرعية]].
  
فإذا كان لديك كائن سبق إنشاؤه في شيفرة برمجية ومُررت إليه قيمة النوع المشفر. بعد استخدام تابع إعادة التصميم، تظهر عدة أصناف فرعية، ومنها، تحتاج إلى إنشاء كائنات اعتمادًا على قيمة النوع المشفر. ويعد تغيير المُنشئ الأصلي بشكل يجعل إعادة كائنات أصناف فرعية شيئًا مستحيلًا، وبدلًا من ذلك يُنشأ تابع تصميم ثابت يعيد كائنات الأصناف الضرورية، وبعد ذلك يستبدل جميع استدعاءات المُنشئ الأصلي.
+
فإذا كان لديك كائن سبق إنشاؤه في شيفرة برمجية ومُررت إليه قيمة النوع المشفر؛ فبعد استخدام تابع إعادة التصميم، تظهر عدة أصناف فرعية، ومنها، تحتاج إلى إنشاء كائنات اعتمادًا على قيمة النوع المشفر. ويعد تغيير المُنشئ الأصلي بشكل يجعل إعادة كائنات أصناف فرعية شيئًا مستحيلًا، وبدلًا من ذلك يُنشأ تابع تصميم ثابت يعيد كائنات الأصناف الضرورية، وبعد ذلك يستبدل جميع استدعاءات المُنشئ الأصلي.
  
يمكن أيضًا استخدام توابع التصميم في حالات أخرى، عندما لا تكون المُنشِآت على القدر المناسب للمهمة. ويمكن أن تكون هامة عند محاولة [[Refactoring/change value to reference|تغيير القيمة إلى مرجع]]. كما يمكن استخدامها أيضا لتحديد أنماط إنشاء مختلفة والتي تتجاوز عدد وأنواع المعاملات.
+
يمكن أيضًا استخدام توابع التصميم في حالات أخرى، عندما لا تكون المُنشِآت على القدر المناسب للمهمة. ويمكن أن تكون مهمة عند محاولة [[Refactoring/change value to reference|تغيير القيمة إلى مرجع]]. كما يمكن استخدامها أيضا لتحديد أنماط إنشاء مختلفة والتي تتجاوز عدد وأنواع المعاملات.
  
 
= فوائد تطبيق الحل =
 
= فوائد تطبيق الحل =
 
* لا يعيد تابع التصميم كائنًا من الصنف الذي أُستُدعيَ منه بالضرورة. وكثيرًا ما يكون من أصنافه الفرعية، مُختارًا بحسب الوسائط المقدمة إلى التابع.
 
* لا يعيد تابع التصميم كائنًا من الصنف الذي أُستُدعيَ منه بالضرورة. وكثيرًا ما يكون من أصنافه الفرعية، مُختارًا بحسب الوسائط المقدمة إلى التابع.
 
* يمكن لتابع التصميم أن يكون له اسم أفضل يصف ما يفعله ويعيده وكيف، على سبيل المثال <code>Troops::GetCrew(myTank)‎</code>.
 
* يمكن لتابع التصميم أن يكون له اسم أفضل يصف ما يفعله ويعيده وكيف، على سبيل المثال <code>Troops::GetCrew(myTank)‎</code>.
* يمكن لتابع التصميم أن يعيد كائنًا مُنشَأً بالفعل، على عكس المُنشئ، الذي يخلق دائما مثيل جديد.
+
* يمكن لتابع التصميم أن يعيد كائنًا مُنشَأً بالفعل، على عكس المُنشئ، الذي يخلق دائما نسخة جديدة.
  
 
= آلية الحل =
 
= آلية الحل =
# أنشئ تابع تصميم. ثم ضع استدعاءً للمُنشئ الحالي داخله.
+
# أنشئ تابع تصميم ثم ضع استدعاءً للمُنشئ الحالي داخله.
 
# استبدل جميع استدعاءات المُنشئ باستدعاءات إلى تابع التصميم.
 
# استبدل جميع استدعاءات المُنشئ باستدعاءات إلى تابع التصميم.
 
# اجعل المُنشئ خاصًا.
 
# اجعل المُنشئ خاصًا.
سطر 90: سطر 110:
 
* [[Refactoring/change value to reference|تغيير القيمة إلى مرجع (Change Value to Reference)]].
 
* [[Refactoring/change value to reference|تغيير القيمة إلى مرجع (Change Value to Reference)]].
 
* [[Refactoring/replace type code with subclasses|تبديل رموز الأنواع بالأصناف الفرعية (Replace Type Code with Subclasses)]].
 
* [[Refactoring/replace type code with subclasses|تبديل رموز الأنواع بالأصناف الفرعية (Replace Type Code with Subclasses)]].
* [[Refactoring/factory-method|تابع التصميم (Factory Method)]].
 
  
 
== مصادر ==
 
== مصادر ==
سطر 96: سطر 115:
 
[[تصنيف:Refactoring]]
 
[[تصنيف:Refactoring]]
 
[[تصنيف:Refactoring Techniques]]
 
[[تصنيف:Refactoring Techniques]]
[[تصنيف:Simplifying Method Calls]]
+
[[تصنيف:Refactoring Simplifying Method Calls]]

المراجعة الحالية بتاريخ 08:36، 26 فبراير 2019

المشكلة

لديك مُنشئ (constructor) معقد يقوم بما هو أكثر من مجرد وضع قيم المعامل في حقول الكائن.

الحل

إنشاء تابع تصميم واستخدامه لاستبدال استدعاءات المُنشئ.

مثال

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

وجود منشئ معقد للصنف Employee:

في لغة Java:

class Employee {
  Employee(int type) {
    this.type = type;
  }
  //...
}

في لغة C#‎:

public class Employee 
{
  public Employee(int type) 
  {
    this.type = type;
  }
  //...
}

في لغة PHP:

class Employee {
  // ...
  public function __construct($type) {
   $this->type = $type;
  }
  // ...
}

في لغة TypeScript:

class Employee {
  constructor(type: number) {
    this.type = type;
  }
  //...
}

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

إنشاء تابع تصميم واستبداله بالمنشئ:

في لغة Java:

class Employee {
  static Employee create(int type) {
    employee = new Employee(type);
    // نفذ بعض الأمور المعقدة والضخمة هنا
    return employee;
  }
  //...
}

في لغة C#‎:

public class Employee
{
  public static Employee Create(int type)
  {
    employee = new Employee(type);
    // نفذ بعض الأمور المعقدة والضخمة هنا
    return employee;
  }
  //...
}

في لغة PHP:

class Employee {
  // ...
  static public function create($type) {
    $employee = new Employee($type);
    // نفذ بعض الأمور المعقدة والضخمة هنا
    return $employee;
  }
  // ...
}

في لغة TypeScript:

class Employee {
  static create(type: number): Employee {
    let employee = new Employee(type);
    // نفذ بعض الأمور المعقدة والضخمة هنا
    return employee;
  }
  //...
}

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

يرتبط السبب الأكثر وضوحًا لاستخدام تقنية إعادة التصميم هذه باستبدال شيفرة النوع بالأصناف الفرعية.

فإذا كان لديك كائن سبق إنشاؤه في شيفرة برمجية ومُررت إليه قيمة النوع المشفر؛ فبعد استخدام تابع إعادة التصميم، تظهر عدة أصناف فرعية، ومنها، تحتاج إلى إنشاء كائنات اعتمادًا على قيمة النوع المشفر. ويعد تغيير المُنشئ الأصلي بشكل يجعل إعادة كائنات أصناف فرعية شيئًا مستحيلًا، وبدلًا من ذلك يُنشأ تابع تصميم ثابت يعيد كائنات الأصناف الضرورية، وبعد ذلك يستبدل جميع استدعاءات المُنشئ الأصلي.

يمكن أيضًا استخدام توابع التصميم في حالات أخرى، عندما لا تكون المُنشِآت على القدر المناسب للمهمة. ويمكن أن تكون مهمة عند محاولة تغيير القيمة إلى مرجع. كما يمكن استخدامها أيضا لتحديد أنماط إنشاء مختلفة والتي تتجاوز عدد وأنواع المعاملات.

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

  • لا يعيد تابع التصميم كائنًا من الصنف الذي أُستُدعيَ منه بالضرورة. وكثيرًا ما يكون من أصنافه الفرعية، مُختارًا بحسب الوسائط المقدمة إلى التابع.
  • يمكن لتابع التصميم أن يكون له اسم أفضل يصف ما يفعله ويعيده وكيف، على سبيل المثال Troops::GetCrew(myTank)‎.
  • يمكن لتابع التصميم أن يعيد كائنًا مُنشَأً بالفعل، على عكس المُنشئ، الذي يخلق دائما نسخة جديدة.

آلية الحل

  1. أنشئ تابع تصميم ثم ضع استدعاءً للمُنشئ الحالي داخله.
  2. استبدل جميع استدعاءات المُنشئ باستدعاءات إلى تابع التصميم.
  3. اجعل المُنشئ خاصًا.
  4. تحقق من شيفرة المُنشئ وحاول عزل الشيفرة غير ذات الصلة المباشرة بإنشاء كائن من الصنف الحالي، وانقل هذه شيفرة إلى تابع التصميم.

انظر أيضًا

مصادر