---
title: "إدخال تابع خارجي (Introduce Foreign Method)"
type: "refactoring-technique"
slug: "introduce-foreign-method"
url: "http://localhost:3000/ar/introduce-foreign-method.md"
category: "نقل الميزات بين الكائنات"
description: "المشكلة: لا تحتوي فئة أدوات (Utility Class) على التابع الذي تحتاجه ولا يمكنك إضافة التابع إلى الفئة. الحل: أضف التابع إلى فئة عميلة (Client Class) ومرر كائناً من فئة الأدوات إليها كمعامل."
languages: ["java", "csharp", "php", "python", "typescript"]
---
# إدخال تابع خارجي (Introduce Foreign Method)

> المشكلة: لا تحتوي فئة أدوات (Utility Class) على التابع الذي تحتاجه ولا يمكنك إضافة التابع إلى الفئة. الحل: أضف التابع إلى فئة عميلة (Client Class) ومرر كائناً من فئة الأدوات إليها كمعامل.

## المشكلة

لا تحتوي فئة أدوات (Utility Class) على التابع الذي تحتاجه ولا يمكنك إضافة التابع إلى الفئة.

## الحل

أضف التابع إلى فئة عميلة (Client Class) ومرر كائناً من فئة الأدوات إليها كمعامل.

## دواعي إعادة الهيكلة

لديك كود يستخدم بيانات وتوابع فئة معينة. وتدرك أن هذا الكود سيبدو ويعمل بشكل أفضل بكثير داخل تابع جديد في تلك الفئة. لكن لا يمكنك إضافة التابع إليها لأن الفئة موجودة في مكتبة خارجية (Third-party library) على سبيل المثال.

هذه التقنية تقدم فائدة كبيرة عندما يتكرر الكود الذي تريد نقله إلى التابع عدة مرات في أماكن مختلفة من برنامجك.

بما أنك تمرر كائن فئة الأدوات كمعامل للتابع الجديد، فلديك إمكانية الوصول إلى جميع حقوله. وداخل هذا التابع، يمكنك فعل كل ما تريده تقريباً، كما لو كان التابع جزءاً من فئة الأدوات نفسها.

## الفوائد

* يزيل تكرار الكود. إذا كان الكود مكرراً في عدة أماكن، يمكنك استبدال هذه الأجزاء باستدعاء تابع. هذا أفضل من التكرار حتى مع الأخذ في الاعتبار أن التابع الخارجي يقع في مكان غير مثالي.

## كيفية إعادة الهيكلة

1. أنشئ تابعاً جديداً في فئة العميل (Client class).
2. في هذا التابع، أنشئ معاملاً يُمَرَّر من خلاله كائن فئة الأدوات (Utility class). إذا كان بالإمكان الحصول على هذا الكائن من فئة العميل، فلا داعي لإنشاء هذا المعامل.
3. استخرج أجزاء الكود ذات الصلة إلى هذا التابع واستبدلها باستدعاءات للتابع.
4. تأكد من ترك علامة _Foreign method (تابع خارجي)_ في التعليقات المرافقة للتابع مع نصيحة لنقل هذا التابع إلى فئة الأدوات إذا أصبح ذلك ممكناً لاحقاً. سيسهل هذا فهم سبب وجود هذا التابع في هذه الفئة بالتحديد لمن سيقوم بصيانة البرنامج في المستقبل.
## Relations

**Similar techniques**

- [إدخال امتداد محلي (Introduce Local Extension)](/ar/introduce-local-extension.md)

**Eliminates smells**

- [فئة المكتبة غير المكتملة](/ar/smells/incomplete-library-class.md)

## Code Examples

### java

```java
// Before
class Report {
  // ...
  void sendReport() {
    Date nextDay = new Date(previousEnd.getYear(),
      previousEnd.getMonth(), previousEnd.getDate() + 1);
    // ...
  }
}

// After
class Report {
  // ...
  void sendReport() {
    Date newStart = nextDay(previousEnd);
    // ...
  }
  private static Date nextDay(Date arg) {
    return new Date(arg.getYear(), arg.getMonth(), arg.getDate() + 1);
  }
}
```

### csharp

```csharp
// Before
class Report 
{
  // ...
  void SendReport() 
  {
    DateTime nextDay = previousEnd.AddDays(1);
    // ...
  }
}

// After
class Report 
{
  // ...
  void SendReport() 
  {
    DateTime nextDay = NextDay(previousEnd);
    // ...
  }
  private static DateTime NextDay(DateTime date) 
  {
    return date.AddDays(1);
  }
}
```

### php

```php
// Before
class Report {
  // ...
  public function sendReport() {
    $previousDate = clone $this->previousDate;
    $paymentDate = $previousDate->modify("+7 days");
    // ...
  }
}

// After
class Report {
  // ...
  public function sendReport() {
    $paymentDate = self::nextWeek($this->previousDate);
    // ...
  }
  /**
   * تابع خارجي. يجب أن يكون في Date.
   */
  private static function nextWeek(DateTime $arg) {
    $previousDate = clone $arg;
    return $previousDate->modify("+7 days");
  }
}
```

### python

```python
// Before
class Report:
    # ...
    def sendReport(self):
        nextDay = Date(self.previousEnd.getYear(),
            self.previousEnd.getMonth(), self.previousEnd.getDate() + 1)
        # ...

// After
class Report:
    # ...
    def sendReport(self):
        newStart = self._nextDay(self.previousEnd)
        # ...
        
    def _nextDay(self, arg):
        return Date(arg.getYear(), arg.getMonth(), arg.getDate() + 1)
```

### typescript

```typescript
// Before
class Report {
  // ...
  sendReport(): void {
    let nextDay: Date = new Date(previousEnd.getYear(),
      previousEnd.getMonth(), previousEnd.getDate() + 1);
    // ...
  }
}

// After
class Report {
  // ...
  sendReport() {
    let newStart: Date = nextDay(previousEnd);
    // ...
  }
  private static nextDay(arg: Date): Date {
    return new Date(arg.getFullYear(), arg.getMonth(), arg.getDate() + 1);
  }
}
```

