software referencias programación programacion patrones orientado objetos libro lenguaje ejemplos diseño desde cero java oop circular-dependency

java - referencias - Diseño OO y dependencias circulares.



programacion en java desde cero pdf (4)

Ben,

Comenzaría preguntando si un jugador puede (lógicamente, legalmente) retirarse del equipo. Yo diría que el objeto del jugador no sabe en qué equipo está (!), Es parte de un equipo. Por lo tanto, elimine Player#leaveTeam() y haga que todos los cambios de equipo ocurran a través del método Team#removePlayer() .

En el caso de que solo tengas un jugador y necesites eliminarlo de su equipo, entonces podrías tener un método de búsqueda estática en el equipo public static Team findTeam( Player player ) ...

Sé que esto es menos satisfactorio y natural que el método Player#leaveTeam() , pero en mi experiencia, todavía puedes tener un modelo de dominio significativo.

Las referencias bidireccionales (Padre -> Niño y Niño -> Padre) a menudo están llenas de otras cosas, por ejemplo, Recolección de basura, manteniendo la "integridad referencial", etc.

¡El diseño es un compromiso!

Actualmente estoy luchando con un problema de dependencia circular al diseñar mis clases.

Desde que leí sobre el Modelo de Dominio Anémico (algo que estaba haciendo todo el tiempo), realmente he estado tratando de alejarme de la creación de objetos de dominio que eran simplemente "grupos de captadores y definidores" y volví a mis raíces OO.

Sin embargo, el problema a continuación es uno con el que me he topado mucho y no estoy seguro de cómo debería resolverlo.

Digamos que tenemos una clase de equipo , que tiene muchos jugadores . No importa qué deporte es este :) Un equipo puede agregar y eliminar jugadores, de la misma manera que un jugador puede dejar 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 } }

Luego 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... } }

Se puede suponer que ambos métodos (eliminar y dejar) tienen una lógica específica de dominio que debe ejecutarse cada vez que un equipo elimina a un jugador y este abandona un equipo. Por lo tanto, mi primer pensamiento es que cuando un equipo patea a un jugador, removePlayer (...) también debería llamar al método player.leaveTeam () ...

Pero entonces, ¿qué pasa si el jugador está conduciendo la partida? ¿Debería el método leaveTeam () llamar a team.removePlayer (esto)? ¡No sin crear un bucle infinito!

En el pasado , acababa de hacer que estos objetos fueran "tontos", y que una capa de servicio hiciera el trabajo. Pero incluso ahora todavía me queda ese problema: para evitar las dependencias circulares, la capa de servicio todavía tiene todo vinculado, es decir,

public class SomeService { public void leave(Player player, Team team) { team.removePlayer(player); player.leaveTeam(); } }

¿Estoy sobre complicando esto? Tal vez me esté perdiendo algún defecto de diseño obvio. Cualquier comentario sería muy apreciado.

Gracias a todos por las respuestas. Estoy aceptando la solución de 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 tiene un buen punto. En la situación que estaba describiendo, es posible que un jugador abandone un equipo (y tenga en cuenta si está en un equipo o no), así como el equipo que impulsa 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.


La idea es hacer cosas relacionadas con el dominio en diferentes métodos que no se llaman entre sí, pero hace cosas relacionadas con el dominio para su propio objeto, es decir, el método del equipo lo hace para el equipo y el método del jugador lo hace para el jugador

public class Team { private List<Player> players; public void removePlayer(Player player) { removePlayerFromTeam(player); player.removeFromTeam(); } public void removePlayerFromTeam(Player player) { players.remove(player); //domain stuff } } public class Player { private Team team; public void removeFromTeam() { team = null; //domain stuff } public void leaveTeam() { team.removePlayerFromTeam(this); removeFromTeam(); } }


Puede romper la dependencia circular agregando guardias para verificar si el equipo aún tiene el jugador / el jugador todavía está en el equipo. Por ejemplo:

En el Team clase:

public void removePlayer(Player player) { if (players.contains(player)) { players.remove(player); player.leaveTeam(); // Do other admin work when a player leaves } }

Player clase:

public void leaveTeam() { if (team != null) { team.removePlayer(this); team = null; // Do some more player stuff.. } }


public void removePlayer(Player player) { if (players.contains(player)) { players.remove(player); player.leaveTeam(); } }

Lo mismo leaveTeam dentro de la leaveTeam .