Poltergeist (programación informática).
Objeto efímero inapropiado
En la programación informática, un poltergeist (o carromato gitano) es un objeto efímero, normalmente sin estado, que se utiliza para realizar la inicialización o para invocar métodos en otra clase más permanente. Se considera un antipatrón. La definición original es de Michael Akroyd en la conferencia Object World West de 1996:
Igual que un carromato gitano o un poltergeist aparece y desaparece de forma misteriosa, así lo hace este objeto de corta vida. Como consecuencia, el código es más difícil de mantener y se produce un desperdicio innecesario de recursos. La causa típica de este antipatrón es un diseño deficiente de objetos.
A menudo, un poltergeist puede identificarse por su nombre; estos suelen incluir en el nombre palabras como "Manager", "Controller", "Supervisor", "StartProcess", etc.
A veces, las clases poltergeist se crean porque el programador anticipó la necesidad de una arquitectura más compleja. Por ejemplo, surge un poltergeist si el mismo método actúa a la vez como cliente e invocador en un patrón Command, y el programador anticipa la separación de ambas fases. Sin embargo, esta arquitectura más compleja puede que en realidad nunca llegue a materializarse.
Los poltergeists no deben confundirse con los objetos longevos y portadores de estado de un patrón como el modelo–vista–controlador, ni con los patrones de separación en capas como el patrón business delegate.
Para eliminar un poltergeist, borra la clase e inserta su funcionalidad en la clase invocada, posiblemente mediante herencia o como un mixin.
Se han propuesto métodos para detectar poltergeists en el código con vistas a la refactorización.
Ejemplo
La clase Poltergeist de este ejemplo en C++ puede considerarse un "objeto poltergeist", ya que no añade funcionalidad ni encapsulación adicionales y solo aumenta la complejidad con una abstracción innecesaria.
import std;
using String = std::string;
// Clase Poltergeist que solo guarda un puntero, pero no añade ningún comportamiento útil
class Poltergeist {
private:
String* s; // puntero a string, pero la clase en sí no hace nada útil
public:
explicit Poltergeist(String* s):
s{s} {}
~Poltergeist() {
delete s;
}
[[nodiscard]]
String get() const noexcept {
return s;
}
// Sin comportamiento adicional ni funcionalidad útil
};
int main() {
// Crear un objeto Poltergeist que solo guarda un puntero a la cadena
Poltergeist p(new String("Hello, world!"));
// Solo pasa los datos de un lado a otro sin aportar valor
std::println(*p.get());
return 0;
}
En su lugar, esto podría hacerse de forma más apropiada usando un puntero inteligente.
import std;
using String = std::string;
template <typename T>
using UniquePtr = std::unique_ptr<T>;
// Usar punteros inteligentes directamente para gestionar la memoria
UniquePtr<String> s = std::make_unique<String>("Hello, World!");
std::println(*s);
Otro ejemplo de objeto poltergeist/carromato gitano es el siguiente, donde UserCreator se instancia solo para realizar algunas acciones básicas.
import std;
using String = std::string;
class UserManager {
public:
void createUser(const String& name) {
std::println("User created: {}", name);
}
};
// La clase poltergeist
class UserCreator {
public:
explicit UserCreator(const String& name) {
UserManager manager;
manager.createUser(name);
}
};
int main() {
// Crear un poltergeist solo para llamar a createUser()
UserCreator("Alice");
UserCreator("Bob");
}
Esto podría hacerse de forma más apropiada de la siguiente manera, evitando por completo cualquier clase poltergeist:
// Evitar por completo el poltergeist UserCreator
int main() {
UserManager manager;
manager.createUser("Alice");
manager.createUser("Bob");
}