الفرق بين المراجعتين لصفحة: «Refactoring/pull up constructor body»

من موسوعة حسوب
أنشأ الصفحة ب'<noinclude>{{DISPLAYTITLE: سحب متن المُنشِئ لأعلى (Pull Up Constructor Body)}}</noinclude> == المشكلة == تحتوي الأصناف الفرع...'
 
ط مراجعة وتدقيق.
 
سطر 4: سطر 4:


== الحل ==
== الحل ==
إنشاء مُنشئ صنف فائق ونقل الشيفرة المماثلة في الأصناف الفرعية إليه. استدعاء مُنشئ الصنف الفائق في مُنشِئات الصنف الفرعي.
إنشاء مُنشئ صنف أب ونقل الشيفرة المماثلة في الأصناف الفرعية إليه. استدعاء مُنشئ الصنف الأب في مُنشِئات الصنف الفرعي.


=== مثال ===
=== مثال ===


==== قبل إعادة التصميم ====
==== قبل إعادة التصميم ====
في لغة Java:<syntaxhighlight lang="java">
احتواء الصنف الفرعي <code>Manager</code> المشتق من الصنف <code>Employee</code> على منشئ متطابق بنسبة كبيرة:
 
في لغة [[Java]]:<syntaxhighlight lang="java">
class Manager extends Employee {
class Manager extends Employee {
   public Manager(String name, String id, int grade) {
   public Manager(String name, String id, int grade) {
سطر 18: سطر 20:
   //...
   //...
}
}
</syntaxhighlight>في لغة C#‎:<syntaxhighlight lang="c#">
</syntaxhighlight>في لغة [[C#]]‎:<syntaxhighlight lang="c#">
public class Manager: Employee  
public class Manager: Employee  
{
{
سطر 29: سطر 31:
   //...
   //...
}
}
</syntaxhighlight>في لغة PHP:<syntaxhighlight lang="php">
</syntaxhighlight>في لغة [[PHP]]:<syntaxhighlight lang="php">
class Manager extends Employee {
class Manager extends Employee {
   public function __construct($name, $id, $grade) {
   public function __construct($name, $id, $grade) {
سطر 38: سطر 40:
   // ...
   // ...
}
}
</syntaxhighlight>في لغة Python:<syntaxhighlight lang="python">
</syntaxhighlight>في لغة [[Python]]:<syntaxhighlight lang="python">
class Manager(Employee):
class Manager(Employee):
     def __init__(self, name, id, grade):
     def __init__(self, name, id, grade):
سطر 45: سطر 47:
         self.grade = grade
         self.grade = grade
     #...
     #...
</syntaxhighlight>في لغة [[TypeScript]]:<syntaxhighlight lang="typescript">
class Manager extends Employee {
  constructor(name: string, id: string, grade: number) {
    this.name = name;
    this.id = id;
    this.grade = grade;
  }
  //...
}
</syntaxhighlight>
</syntaxhighlight>


==== بعد إعادة التصميم ====
==== بعد إعادة التصميم ====
في لغة Java:<syntaxhighlight lang="java">
جعل الصنف <code>Manager</code> الفرعي يرث منشئ الصنف الأب <code>Employee</code> مع إضافة الخاصية <code>grade</code>:
 
في لغة [[Java]]:<syntaxhighlight lang="java">
class Manager extends Employee {
class Manager extends Employee {
   public Manager(String name, String id, int grade) {
   public Manager(String name, String id, int grade) {
سطر 56: سطر 69:
   //...
   //...
}
}
</syntaxhighlight>في لغة C#‎:<syntaxhighlight lang="c#">
</syntaxhighlight>في لغة [[C#]]‎:<syntaxhighlight lang="c#">
public class Manager: Employee  
public class Manager: Employee  
{
{
سطر 65: سطر 78:
   //...
   //...
}
}
</syntaxhighlight>في لغة PHP:<syntaxhighlight lang="php">
</syntaxhighlight>في لغة [[PHP]]:<syntaxhighlight lang="php">
class Manager extends Employee {
class Manager extends Employee {
   public function __construct($name, $id, $grade) {
   public function __construct($name, $id, $grade) {
سطر 74: سطر 87:
}
}


</syntaxhighlight>في لغة Python:<syntaxhighlight lang="python">
</syntaxhighlight>في لغة [[Python]]:<syntaxhighlight lang="python">
class Manager(Employee):
class Manager(Employee):
     def __init__(self, name, id, grade):
     def __init__(self, name, id, grade):
سطر 80: سطر 93:
         self.grade = grade
         self.grade = grade
     #...
     #...
</syntaxhighlight>في لغة [[TypeScript]]:<syntaxhighlight lang="typescript">
class Manager extends Employee {
  constructor(name: string, id: string, grade: number) {
    super(name, id);
    this.grade = grade;
  }
  //...
}
</syntaxhighlight>
</syntaxhighlight>


== لم إعادة التصميم؟ ==
== لم إعادة التصميم؟ ==
كيف تختلف تقنية إعادة التصميم هذه عن [[Refactoring/pull up method|سحب التابع لأعلى]]؟
كيف تختلف تقنية إعادة التصميم هذه عن [[Refactoring/pull up method|سحب التابع لأعلى]]؟
# في جافا، لا يمكن أن ترث الأصنافُ الفرعية منشئ لذا لا يمكنك ببساطة تطبيق [[Refactoring/pull up method|سحب التابع لأعلى]] إلى منشئ صنف فرعي وحذفه بعد إزالة جميع شيفرة المُنشِئ إلى الصنف الفائق. بالإضافة إلى إنشاء مُنشئ في الصنف الفائق، من الضروري أن يكون هناك مُنشِئات في الأصناف الفرعية مع تفويض بسيط إلى مُنشِئ الصنف الفائق.
# في جافا، لا يمكن أن ترث الأصنافُ الفرعية منشئ الصنف الأب، لذا لا يمكنك ببساطة تطبيق [[Refactoring/pull up method|سحب التابع لأعلى]] إلى منشئ صنف فرعي وحذفه بعد إزالة جميع شيفرة المُنشِئ إلى الصنف الأب. بالإضافة إلى إنشاء مُنشئ في الصنف الأب، من الضروري أن يكون هناك مُنشِئات في الأصناف الفرعية مع تفويض بسيط إلى مُنشِئ الصنف الأب.
# في C++‎ و Java (إذا أنت لم تستدعي منشئ الصنف الفائق صراحةً) يُستدعى منشئ الصنف الفائق تلقائيًا قبل منشئ الصنف الفرعي، مما يجعل من الضروري نقل الشيفرة المشتركة فقط من بداية مُنشِئات الصنف الفرعي (بما أنك لن تكون قادرًا على استدعاء منشِئ الصنف الفائق من أي مكان عشوائي في منشِئ الصنف الفرعي).
# في C++‎ و Java (إذا أنت لم تستدعي منشئ الصنف الأب صراحةً) يُستدعَى منشئ الصنف الأب تلقائيًا قبل منشئ الصنف الفرعي، مما يجعل من الضروري نقل الشيفرة المشتركة فقط من بداية مُنشِئات الصنف الفرعي (بما أنك لن تكون قادرًا على استدعاء منشِئ الصنف الأب من أي مكان عشوائي في منشِئ الصنف الفرعي).
# في معظم لغات البرمجة، يمكن أن يكون لمنشئ صنف فرعي قائمته الخاصة من المعاملات المختلفة عن معاملات الصنف الفائق. لذلك يجب إنشاء مُنشئ الصنف الفائق فقط مع المعاملات التي يحتاجها حقا.
# في معظم لغات البرمجة، يمكن أن يكون لمنشئ صنف فرعي قائمته الخاصة من المعاملات المختلفة عن معاملات الصنف الأب. لذلك يجب إنشاء مُنشئ الصنف الأب فقط مع المعاملات التي يحتاجها حقًا.


== آلية الحل ==
== آلية الحل ==
# أنشئ مُنشئ في الصنف الفائق.
# أنشئ مُنشئًا (بانيًا) في الصنف الأب.
# استخرج الشيفرة المشتركة من بداية منشئ كل صنفٍ فرعي إلى منشئ الصنف الفائق. قبل القيام بذلك، حاول نقل أكبر قدر ممكن من الشيفرة الشائعة إلى بداية المُنشئ.
# استخرج الشيفرة المشتركة من بداية منشئ كل صنفٍ فرعي إلى منشئ الصنف الأب. قبل القيام بذلك، حاول نقل أكبر قدر ممكن من الشيفرة الشائعة إلى بداية المُنشئ.
# ضع استدعاء مُنشئ الصنف الفائق في السطر الأول في مُنشئات الصنف الفرعي.
# ضع استدعاء مُنشئ الصنف الأب في السطر الأول في مُنشئات الصنف الفرعي.


== انظر أيضًا ==
== انظر أيضًا ==
سطر 102: سطر 123:
[[تصنيف:Refactoring]]
[[تصنيف:Refactoring]]
[[تصنيف:Refactoring Techniques]]
[[تصنيف:Refactoring Techniques]]
[[تصنيف:Dealing with Generalization]]
[[تصنيف:Refactoring Dealing with Generalization]]

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

المشكلة

تحتوي الأصناف الفرعية على مُنشِئات لها شيفرة متطابقة في أغلبها.

الحل

إنشاء مُنشئ صنف أب ونقل الشيفرة المماثلة في الأصناف الفرعية إليه. استدعاء مُنشئ الصنف الأب في مُنشِئات الصنف الفرعي.

مثال

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

احتواء الصنف الفرعي Manager المشتق من الصنف Employee على منشئ متطابق بنسبة كبيرة:

في لغة Java:

class Manager extends Employee {
  public Manager(String name, String id, int grade) {
    this.name = name;
    this.id = id;
    this.grade = grade;
  }
  //...
}

في لغة C#‎:

public class Manager: Employee 
{
  public Manager(string name, string id, int grade) 
  {
    this.name = name;
    this.id = id;
    this.grade = grade;
  }
  //...
}

في لغة PHP:

class Manager extends Employee {
  public function __construct($name, $id, $grade) {
    $this->name = $name;
    $this->id = $id;
    $this->grade = $grade;
  }
  // ...
}

في لغة Python:

class Manager(Employee):
    def __init__(self, name, id, grade):
        self.name = name
        self.id = id
        self.grade = grade
    #...

في لغة TypeScript:

class Manager extends Employee {
  constructor(name: string, id: string, grade: number) {
    this.name = name;
    this.id = id;
    this.grade = grade;
  }
  //...
}

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

جعل الصنف Manager الفرعي يرث منشئ الصنف الأب Employee مع إضافة الخاصية grade:

في لغة Java:

class Manager extends Employee {
  public Manager(String name, String id, int grade) {
    super(name, id);
    this.grade = grade;
  }
  //...
}

في لغة C#‎:

public class Manager: Employee 
{
  public Manager(string name, string id, int grade): base(name, id)
  {
    this.grade = grade;
  }
  //...
}

في لغة PHP:

class Manager extends Employee {
  public function __construct($name, $id, $grade) {
    parent::__construct($name, $id);
    $this->grade = $grade;
  }
  // ...
}

في لغة Python:

class Manager(Employee):
    def __init__(self, name, id, grade):
        Employee.__init__(name, id)
        self.grade = grade
    #...

في لغة TypeScript:

class Manager extends Employee {
  constructor(name: string, id: string, grade: number) {
    super(name, id);
    this.grade = grade;
  }
  //...
}

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

كيف تختلف تقنية إعادة التصميم هذه عن سحب التابع لأعلى؟

  1. في جافا، لا يمكن أن ترث الأصنافُ الفرعية منشئ الصنف الأب، لذا لا يمكنك ببساطة تطبيق سحب التابع لأعلى إلى منشئ صنف فرعي وحذفه بعد إزالة جميع شيفرة المُنشِئ إلى الصنف الأب. بالإضافة إلى إنشاء مُنشئ في الصنف الأب، من الضروري أن يكون هناك مُنشِئات في الأصناف الفرعية مع تفويض بسيط إلى مُنشِئ الصنف الأب.
  2. في C++‎ و Java (إذا أنت لم تستدعي منشئ الصنف الأب صراحةً) يُستدعَى منشئ الصنف الأب تلقائيًا قبل منشئ الصنف الفرعي، مما يجعل من الضروري نقل الشيفرة المشتركة فقط من بداية مُنشِئات الصنف الفرعي (بما أنك لن تكون قادرًا على استدعاء منشِئ الصنف الأب من أي مكان عشوائي في منشِئ الصنف الفرعي).
  3. في معظم لغات البرمجة، يمكن أن يكون لمنشئ صنف فرعي قائمته الخاصة من المعاملات المختلفة عن معاملات الصنف الأب. لذلك يجب إنشاء مُنشئ الصنف الأب فقط مع المعاملات التي يحتاجها حقًا.

آلية الحل

  1. أنشئ مُنشئًا (بانيًا) في الصنف الأب.
  2. استخرج الشيفرة المشتركة من بداية منشئ كل صنفٍ فرعي إلى منشئ الصنف الأب. قبل القيام بذلك، حاول نقل أكبر قدر ممكن من الشيفرة الشائعة إلى بداية المُنشئ.
  3. ضع استدعاء مُنشئ الصنف الأب في السطر الأول في مُنشئات الصنف الفرعي.

انظر أيضًا

مصادر