Objeto deus.
Um objeto deus é um antipadrão: uma única classe que sabe ou faz demais e concentra a maior parte dos dados e do comportamento do programa.
Na programação orientada a objetos , um objeto deus (do inglês god object), também conhecido como objeto monstro, é um objeto que sabe demais ou faz demais. O objeto deus é um exemplo de um antipadrão em projetos de software.
Uma técnica de programação comum é separar um problema grande em vários problemas menores (uma estratégia de divisão e conquista) e criar soluções para cada um deles. Uma vez resolvidos os problemas menores, o grande problema é resolvido como um todo. Portanto, um objeto destinado a resolver um pequeno problema precisa saber apenas sobre si mesmo e há apenas um pequeno conjunto de problemas que um objeto precisa resolver: seus próprios problemas.
Em contraste, um programa que emprega um objeto deus não segue essa abordagem. A maior parte da funcionalidade geral desse programa é codificada em um único objeto "onisciente", que mantém a maior parte das informações do programa inteiro e também fornece a maioria dos métodos para manipular esses dados. Como esse objeto contém muitos dados e requer tantos métodos, seu papel no programa se torna semelhante a deus (onisciente e abrangente). Em vez dos vários objetos do programa se comunicarem diretamente entre si, todos acabam dependendo do objeto deus para a maioria de suas informações e interações. Como esse objeto é fortemente acoplado a tantas outras partes do código, a manutenção se torna mais difícil do que seria em um projeto dividido de maneira mais uniforme. Por exemplo, alterações feitas no objeto deus para beneficiar uma certa rotina podem ter efeitos indesejados em outras rotinas não relacionadas.
Um objeto deus em programação orientada a objetos é análogo a não usar sub-rotinas em programação procedural, ou a usar muitas variáveis globais para armazenar informações de estado.
Enquanto a criação de um objeto deus é tipicamente considerada uma prática de programação incorreta, essa técnica é ocasionalmente usada em ambientes de programação rígidos (como microcontroladores), onde o aumento de desempenho e centralização do controle são mais importantes do que a manutenção e a elegância de programação.
Veja também
- Código espaguete – outro antipadrão de estrutura de código
Exemplo
A classe GameManager deste exemplo em C++ é um objeto deus típico: gerencia os jogadores, cuida da lógica do jogo, desenha a tela, trata a entrada e salva o jogo em disco.
import std;
using std::string;
using std::vector;
class GameManager {
private:
vector<string> players;
int score = 0;
bool running = false;
public:
GameManager() = default;
~GameManager() = default;
void addPlayer(const string& name) {
players.push_back(name);
std::println("Added player: {}", name);
}
void listPlayers() const {
std::println("Players:");
for (const string& p : players) {
std::println(" - {}", p);
}
}
void startGame() {
running = true;
score = 0;
std::println("Game started!");
}
void updateGame() {
if (running) {
score += 10;
std::println("Score updated: {}", score);
}
}
void endGame() {
running = false;
std::println("Game over! Final score: {}", score);
}
void draw() {
std::println("[Rendering Game Screen]");
}
void handleInput(const string& input) {
if (input == "quit") {
endGame();
} else if (input == "score") {
std::println("Current score: {}", score);
} else {
std::println("Unknown input");
}
}
void saveGame() {
std::println("Saving game state to disk...");
}
void loadGame() {
std::println("Loading game state from disk...");
}
void run() {
// ...
}
};
É mais adequado distribuir essas responsabilidades entre classes separadas:
import std;
using std::string;
using std::vector;
class PlayerManager {
private:
vector<string> players;
public:
PlayerManager() = default;
~PlayerManager() = default;
void addPlayer(const string& name) {
players.push_back(name);
std::println("Added player: {}", name);
}
void listPlayers() const {
std::println("Players:");
for (const string& p : players) {
std::println(" - {}", p);
}
}
};
class GameLogic {
private:
int score = 0;
bool running = false;
public:
GameLogic() = default;
~GameLogic() = default;
void startGame() {
running = true;
score = 0;
std::println("Game started!");
}
void updateGame() {
if (running) {
score += 10;
std::println("Score updated: {}", score);
}
}
int getScore() const noexcept {
return score;
}
void endGame() {
running = false;
std::println("Game over! Final score: {}", score);
}
};
class Renderer {
public:
Renderer() = default;
~Renderer() = default;
void draw() {
std::println("[Rendering Game Screen]");
}
};
class InputHandler {
private:
GameLogic& logic;
public:
explicit InputHandler(GameLogic& logic):
logic{logic} {}
~InputHandler() = default;
void handleInput(const string& input) {
if (input == "quit") {
logic.endGame();
} else if (input == "score") {
std::println("Current score: {}", logic.getScore());
} else {
std::println("Unknown input");
}
}
};
class SaveSystem {
public:
SaveSystem() = default;
~SaveSystem() = default;
void saveGame() {
std::println("Saving game state to disk...");
}
void loadGame() {
std::println("Loading game state from disk...");
}
};
class GameManager {
private:
PlayerManager players;
GameLogic logic;
Renderer renderer;
InputHandler input{logic};
SaveSystem saves;
public:
GameManager() = default;
~GameManager() = default;
void run() {
// ...
}
};
Agora cada classe tem um único motivo para mudar, e GameManager apenas as conecta. Esse é o remédio habitual para uma classe grande, aplicado com a refatoração Extrair Classe.
Adaptado do artigo da Wikipédia “Objeto deus” (revisão 54088296), disponível sob a licença CC BY-SA 4.0; o texto foi editado e exemplos foram adicionados.