TL; DR;
Nessuno. Avere un'autorità centrale che faccia la contabilità, ma iniettarla come delegato sia per i giocatori che per le partite. Sembra che Match
abbia un elenco di Players
e Player abbia avuto un riferimento alla sua corrispondenza. Non possiamo fidarci di giocatori o partite che impongono la regola 1P-1M, vero?
Risposta lunga
Ho progettato una soluzione che è una classe chiamata MatchManager
che è responsabile della registrazione e annullamento della registrazione dei giocatori in partite che applicano la regola 1P-1M. Puoi anche chiederlo per un elenco di giocatori per una determinata partita e che cosa corrisponde a un dato giocatore è registrato.
La parte interessante è che MatchManager
è un singleton e ad entrambi i giocatori e le partite viene iniettato il gestore come delegato ai loro metodi.
In questo modo, ogni operazione eseguita da giocatori o fiammiferi è garantita per essere centralizzata e sincronizzata.
Ovviamente se vuoi che questa soluzione sia sicura per i thread devi usare versioni thread safe delle classi di raccolta utilizzate.
Mostrami il codice
== > Match.java < ==
package matches;
import java.util.ArrayList;
import java.util.List;
public class Match {
private MatchManager matchManager;
public Match(MatchManager matchManager){
this.matchManager = matchManager;
}
public void addPlayer(Player player) throws PlayerAlreadyInAnotherMatchExcepction {
this.matchManager.registerPlayerInMatch(this, player);
}
public void removePlayer(Player player) throws PlayerNotInMatchException {
this.matchManager.unregisterPlayerFromMatch(this, player);
}
public List<Player> getMatchPlayers() throws MatchNotRegisteredException{
return this.matchManager.getMatchPlayers(this);
}
}
== > Player.java < ==
package matches;
public class Player {
private MatchManager matchManager;
public Player(MatchManager matchManager){
this.matchManager = matchManager;
}
public Match getMatch() {
return this.matchManager.getMatch(this);
}
}
== > MatchManager.java < ==
package matches;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class MatchManager {
private static MatchManager instance;
private MatchManager(){}
public static MatchManager getInstance(){
if (instance == null){
instance = new MatchManager();
}
return instance;
}
Map<Player,Match> regPlayersToMatches = new HashMap<Player,Match>();
Map<Match,List<Player>> regMatchesToPlayers = new HashMap<Match,List<Player>>();
public void registerPlayerInMatch(Match match, Player player)
throws PlayerAlreadyInAnotherMatchExcepction {
Match m = this.regPlayersToMatches.get(player);
List<Player> p;
if ( m == null ){
this.regPlayersToMatches.put(player, match);
p = new ArrayList<Player>();
p.add(player);
this.regMatchesToPlayers.put(match, p);
} else {
throw new PlayerAlreadyInAnotherMatchExcepction();
}
}
public void unregisterPlayerFromMatch(Match match, Player player)
throws PlayerNotInMatchException {
List<Player> p = this.regMatchesToPlayers.get(match);
if (p==null){
throw new PlayerNotInMatchException();
}
if (p.contains(player)){
throw new PlayerNotInMatchException();
}
this.regPlayersToMatches.remove(player);
this.regMatchesToPlayers.remove(match);
}
public boolean isPlayerInMatch(Match match, Player player){
List<Player> p = this.regMatchesToPlayers.get(match);
if (p==null){
return false;
}
return (p.contains(player));
}
public List<Player> getMatchPlayers(Match match) throws MatchNotRegisteredException{
List<Player> p = this.regMatchesToPlayers.get(match);
if (p==null){
throw new MatchNotRegisteredException();
}
return new ArrayList<Player>(p);
}
public Match getMatch(Player player) {
return this.regPlayersToMatches.get(player);
}
}
== > PlayerAlreadyInAnotherMatchExcepction.java < ==
package matches;
public class PlayerAlreadyInAnotherMatchExcepction extends Exception {
}
== > PlayerNotInMatchException.java < ==
package matches;
public class PlayerNotInMatchException extends Exception {
}
== > MatchNotRegisteredException.java < ==
package matches;
public class MatchNotRegisteredException extends Exception {
}
Nota: non ho usato le interfacce per mantenere la risposta più breve. Se si desidera rispettare il DIP, scrivere interfacce (o classi astratte) per tenere a bada le dipendenze.