---
title: "Введение внешнего метода"
type: "refactoring-technique"
slug: "introduce-foreign-method"
url: "http://localhost:3000/ru/introduce-foreign-method.md"
category: "Перемещение функций между объектами"
description: "Проблема: Служебный класс не содержит метода, который вам нужен, при этом у вас нет возможности добавить метод в этот класс. Решение: Добавьте метод в клиентский класс и передавайте в него объект служебного класса в качестве аргумента."
languages: ["java", "csharp", "php", "python", "typescript"]
---
# Введение внешнего метода

> Проблема: Служебный класс не содержит метода, который вам нужен, при этом у вас нет возможности добавить метод в этот класс. Решение: Добавьте метод в клиентский класс и передавайте в него объект служебного класса в качестве аргумента.

## Problem

Служебный класс не содержит метода, который вам нужен, при этом у вас нет возможности добавить метод в этот класс.

## Solution

Добавьте метод в клиентский класс и передавайте в него объект служебного класса в качестве аргумента.

## Why Refactor

У вас есть код, который использует данные и методы определённого класса. Вы приходите к выводу, что этот код намного лучше будет смотреться и работать внутри нового метода в этом классе. Однако возможность добавить такой метод в класс у вас отсутствует (например, потому что класс находится в сторонней библиотеке).

Данный рефакторинг особенно выгоден в случаях, когда участок кода, который вы хотите перенести в метод, повторяется несколько раз в различных местах программы.

Так как вы передаёте объект служебного класса в параметры нового метода, у вас есть доступ ко всем его полям. Вы можете делать внутри этого метода практически все, что вам может потребоваться, как если бы метод был частью служебного класса.

## Benefits

* Убирает дублирование кода. Если ваш участок кода повторяется в нескольких местах, вы можете заменить их вызовом метода. Это удобнее дублирования даже с учетом того, что внешний метод находится не там, где хотелось бы.

## How to Refactor

1. Создайте новый метод в клиентском классе.
2. В этом методе создайте параметр, в который будет передаваться объект служебного класса. Если этот объект может быть получен из клиентского класса, параметр можно не создавать.
3. Извлеките волнующие вас участки кода в этот метод и замените их вызовами метода.
4. Обязательно оставьте в комментарии к этому методу метку _Foreign method_ и призыв поместить этот метод в служебный класс, если такая возможность появится в дальнейшем. Это облегчит понимание того, почему этот метод находится в данном классе для тех, кто будет поддерживать программный продукт в будущем.
## Relations

**Similar techniques**

- [Введение локального расширения](/ru/introduce-local-extension.md)

**Eliminates smells**

- [Неполнота библиотечного класса](/ru/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);
    // ...
  }
  /**
   * Foreign method. Should be in 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);
  }
}
```

