Actualmente estoy luchando con un problema de dependencia circular al diseñar mis clases.OO diseño y dependencias circulares
Desde que leí sobre el Anemic Domain Model (algo que hacía todo el tiempo), realmente he estado tratando de evitar crear objetos de dominio que fueran solo "cubos de getters y setters" y regresar a mis raíces OO.
Sin embargo, el problema siguiente es uno con el que me encuentro mucho y no estoy seguro de cómo debería resolverlo.
Digamos que tenemos una clase equipo, que tiene muchos jugadores . No importa qué deporte sea este :) Un equipo puede agregar y eliminar jugadores, de la misma forma en que un jugador puede abandonar un equipo y unirse a otro.
Así que tenemos el equipo, que tiene una lista de jugadores:
public class Team {
private List<Player> players;
// snip.
public void removePlayer(Player player) {
players.remove(player);
// Do other admin work when a player leaves
}
}
entonces tenemos el jugador, que tiene una referencia al Equipo:
public class Player {
private Team team;
public void leaveTeam() {
team = null;
// Do some more player stuff...
}
}
Uno puede asumir que tanto Los métodos (eliminar y salir) tienen una lógica específica de dominio que debe ejecutarse siempre que un equipo elimine un jugador y un jugador deje un equipo. Por lo tanto, lo primero que pensé es que cuando un equipodar una patada al jugador, removePlayer (...) También debe llamar al método player.leaveTeam() ...
Pero ¿y si el jugador está impulsando la partida: ¿debería el método leaveTeam() llamar a team.removePlayer (this)? ¡No sin crear un ciclo infinito!
En el pasado, acababa de hacer estos objetos POJOs "tontos" y tenía una capa de servicio que hacía el trabajo. Pero incluso ahora todavía estoy quedo con ese problema: para evitar dependencias circulares, la capa de servicios todavía tiene vincular todo junto - es decir,
public class SomeService {
public void leave(Player player, Team team) {
team.removePlayer(player);
player.leaveTeam();
}
}
¿Estoy sobre complicando esto? Tal vez me falta algún defecto obvio de diseño. Cualquier comentario sería muy apreciado.
Gracias a todos por las respuestas. Estoy aceptando la solución Grodriguez ya que es la más obvia (no puedo creer que no se me haya ocurrido) y es fácil de implementar. Sin embargo, DecaniBass es un buen punto. En la situación que describo, es posible que un jugador abandone un equipo (y sepa si está en un equipo o no), así como también el equipo que dirige la eliminación. Pero estoy de acuerdo con su punto y no me gusta la idea de que haya dos "puntos de entrada" en este proceso. Gracias de nuevo.
Puede ser solo yo, pero me gusta usar si ... lo más con moderación posible. Me he dado cuenta de que hace que el código sea menos fácil de mantener –
players.remove() devolverá true si se cambió la colección; no es necesario hacer los .contains(). – KarlP
@KarlP: Lo sé, pero pensé que la verificación explícita aclararía la lógica. – Grodriguez