Логотип ConstructiCat
CodeBust.
Навигация по разделу ▾

Полтергейст.

Полтергейст — короткоживущий класс без состояния, который существует только для вызова методов другого класса и добавляет косвенность без поведения.

В программировании полтергейст — это короткоживущий, обычно не имеющий состояния объект, используемый для выполнения инициализации или для вызова методов в другом, более постоянном классе. Он считается антипаттерном. Термин ввёл Майкл Акройд на конференции Object World West в 1996 году: подобно полтергейсту, такой объект загадочно появляется и исчезает. Как следствие, код становится труднее сопровождать, а ресурсы расходуются впустую. Типичная причина этого антипаттерна — плохое проектирование объектов.

Полтергейст часто можно опознать по его имени; в них нередко встречаются такие слова, как «Manager», «Controller», «Supervisor», «StartProcess» и т. п.

Иногда классы-полтергейсты создаются потому, что программист предвосхищал потребность в более сложной архитектуре. Например, полтергейст возникает, если один и тот же метод выступает одновременно и клиентом, и инициатором в паттерне «Команда», и программист предполагает разделить эти две фазы. Однако такая более сложная архитектура в действительности может так и не появиться.

Полтергейсты не следует путать с долгоживущими, несущими состояние объектами паттернов, таких как модель—представление—контроллер, или паттернов, разделяющих уровни, таких как паттерн «Бизнес-делегат».

Чтобы устранить полтергейст, удалите класс и перенесите его функциональность в вызываемый класс, возможно, посредством наследования или в виде примеси (mixin).

Были предложены методы обнаружения полтергейстов в коде для целей рефакторинга.

В терминах рефакторинга лечение — это Встраивание класса. Полтергейст близок к запахам кода Ленивый класс и Посредник.

Пример

В этом примере на C++ полтергейстом является UserCreator: его экземпляр создаётся лишь для того, чтобы создать UserManager, вызвать один его метод и тут же исчезнуть.

import std;

using String = std::string;

class UserManager {
public:
    void createUser(const String& name) {
        std::println("User created: {}", name);
    }
};

// Класс-полтергейст
class UserCreator {
public:
    explicit UserCreator(const String& name) {
        UserManager manager;
        manager.createUser(name);
    }
};

int main() {
    // Создаём полтергейст только ради вызова createUser()
    UserCreator("Alice");
    UserCreator("Bob");
}

Без полтергейста вызывающий код работает с UserManager напрямую, и читать и сопровождать приходится на один класс меньше:

import std;

using String = std::string;

class UserManager {
public:
    void createUser(const String& name) {
        std::println("User created: {}", name);
    }
};

// Без UserCreator: вызывающий код обращается к UserManager напрямую
int main() {
    UserManager manager;
    manager.createUser("Alice");
    manager.createUser("Bob");
}

Адаптировано по статье Википедии “Poltergeist (computer programming)” (версия 1321576717), распространяется по лицензии CC BY-SA 4.0; текст переведён и отредактирован, добавлены примеры.