Suppose I have the following two classes to start off with:
public class Game {
private final Player self;
private final Player opponent;
public Game(final Player self, final Player opponent) {
this.self = Objects.requireNonNull(self);
this.opponent = Objects.requireNonNull(opponent);
}
}
public class Player {
private final String name;
public Player (final String name) {
this.name = Objects.requireNonNull(name);
}
}
Now I have discovered that I need access to the other players (thus to the Game object) in my Player class.
One way to do it is the following, add this to the Player class:
private Game game;
public void setGame(final Game game) {
this.game = Objects.requireNonNull(game);
}
However now it breaks immutability of the game object, are there ways to preserve immutabiity of mutually created objects?
Or do I need to resort to manually imposed mutability and safety (from a regular client perspective, not from a multithreaded synchronization perspective)? Such as throwing an exception whenever someone attempts multiple setGame.
To summarize, this is the mutual dependency I am trying to solve:
Player playerSelf = new Player(/* non-existing game */, "Self");
Player playerOpponent = new Player(/* non-existing game */, "Opponent");
Game game = new Game(playerSelf, playerOpponent);
versus
Game game = new Game(/* non-existing player */, /* non-existing player */);
Player playerSelf = new Player(game, "Self");
Player playerOpponent = new Player(game, "Opponent");
Does there exist a Pattern such as for example the Builder Pattern which aids against an explosion of constructor arguments, which could be solved in a way that breaks immutability if one wanted to avoid the exposion without using the Builder Pattern?
Whenever you have a circular dependency, break it. It will help reduce your code's coupling, increase testability, and keep you sane. Why does Player need access to the other player in the first place? You might be trying to put too much functionality into it. Perhaps you could move that into the Game? Or into, say, a Strategy that's inserted into the Player object?
Also, bear in mind that immutability isn't always the answer. Some things, like the game state, are inherently mutable. Trying to shoehorn them into immutable objects is bound to make life miserable.
Immutablity is a great goal, but 100% immutability is really hard in Java:
Erlang makes every data structure immutable, which is great when the language supports it at that level. Unfortunately Java doesn't support this at the level that it needs to make it effortless and painless.
That said there are multiple solutions to this construction ordering:
Following something similar to the MVC pattern where the Game and Player objects don't even know about each other at all is probably your best solution. But it is the most complex and probably more code than is feasible for an answer here. I might post another answer on that solution by itself, until then.
Here are just a couple of the simpler solutions.
Inner Class Solution :
In this solution, the inner class always has an implicit reference to its outer class. There is no need to pass in the Game object because it is always in scope of the instances of the Player class.
import javax.annotation.Nonnull;
public class Q23726363B
{
public static void main(final String[] args)
{
final Game game = new Game(args[0], args[1]);
}
public static class Game
{
private final Player p1;
private final Player p2;
public Game(#Nonnull final String p1, #Nonnull final String p2)
{
this.p1 = new Player(p1);
this.p2 = new Player(p2);
}
public class Player
{
private final String name;
private Player(#Nonnull final String name) {this.name = name;}
public Game getGame() { return Game.this; }
}
}
}
Factory Method Solution:
Make the Game object the Player object factory. By making the constructors of both objects private you can guarantee that they are constructed correctly and make references functionally immutable by not providing a way to change them publicly.
Use a FactoryMethod, something like the following:
import javax.annotation.Nonnull;
public class Q23726363A
{
public static void main(final String[] args)
{
final Game game = Game.startGame(args[0], args[1]);
}
public static class Game
{
public static Game startGame(#Nonnull final String playerOneName, #Nonnull final String playerTwoName)
{
final Player p1 = new Player(playerOneName);
final Player p2 = new Player(playerTwoName);
final Game game = new Game(p1, p2);
p1.setCurrentGame(game);
p2.setCurrentGame(game);
return game;
}
private final Player player1;
private final Player player2;
private Game(#Nonnull final Player player1, #Nonnull final Player player2)
{
this.player1 = player1;
this.player2 = player2;
}
}
public static class Player
{
private final String name;
private Game currentGame;
private Player(#Nonnull final String name)
{
this.name = name;
}
private void setCurrentGame(#Nonnull final Game currentGame)
{
this.currentGame = currentGame;
}
}
}
Notes:
You might be tempted to create the Player objects in the Game constructor and pass this into the Player objects constructors to set the reference to the Game object.
Resist this temptation, this is called leaking the this reference which in the constructor is bad because it loses all the guarantees that the Game object is completely formed.
Also both of these solutions still have a circular dependency on each other.
The first isn't so bad because the Player class is an inner class of Game. The second is a simple but naive solution that works for small scale applications but not for larger more complex applications.
Related
I am implementing the Snakes and Ladders game. Where Game is one class which has Board, Dice, Players and 2 strategies - Winning Strategy and EndGameStrategy.
Different implementations of EndGameStrategy can be -
If one player wins, the game ends - OnePlayerWonGameEndStrategy
If only 1 player remains at last, the game ends - OnlyOnePlayerLeftGameEndStrategy
The Game model looks as below:
#Builder
#Getter
public class Game {
private Board board;
private Queue<Player> players;
private List<Dice> dices;
private final int MAX_BOARD_SIZE = 1000;
private final int MAX_NUMBER_OF_PLAYERS = 10;
private final int MAX_NUMBER_OF_DICE = 5;
private int totalPlayers;
private GameEndStrategy gameEndStrategy;
private WinningStrategy winningStrategy;
private Queue<Player>leaderBoard;
}
The Client initializes strategies using builder.
Game game = Game.Builder()
.setBoard(board)
.setPlayers(playerList)
.setDices(diceList)
.setGameEndStrategy(new OnlyOnePlayerLeftGameEndStrategy())
.build();
One of the implementation of GameEndStrategy is OnlyOneplayerLeftGameEndStrategy
public class OnlyOnePlayerLeftGameEndStrategy implements GameEndStrategy{
#Override
public Boolean isGameEnd(int activePlayers, int totalPlayers) {
return activePlayers == 1;
}
}
Other implementation is when the first player wins, the game ends
public class OnePlayerWonGameEndStrategy implements GameEndStrategy{
#Override
public Boolean isGameEnd(int activePlayers, int totalPlayers) {
return totalPlayers - activePlayers == 1;
}
}
The client uses the strategy as follows:
while(!game.getGameEndStrategy().isGameEnd(game.getPlayers().size(), game.getTotalPlayers())) {
\\Game logic (Player throws dice, new position is checked
}
Here as parameters of isGameEnd method, should I pass the context class i.e the Game instance as the param? because,
OnlyOnePlayerLeftGameEndStrategy would only need the activePlayers number to check if one one player is left. But, OnePlayerWonGameEndStartegy needs both totalPlayers and activePlayers as params to check if one player has won. Also there could be another strategy in future which would need more params.
So how should we handle changing params? How should we implement the strategy pattern here in this Snakes and Ladders usecase?
I've been looking through some projects of games similar to the one I am developing and I've seen two ways of handling methods to mutate the Player.
Notes: a car, house, and job are the only three things to be handled. (only 3 items this game includes; - so a fourth item like family will never exist) However, this does not mean that no more fields will be added and mutated to the player class. (100+ more fields to be added)
Here is the generic java framework and usage (Which I am using at the moment):
#Data //lombok for setters/getters
public final class Player {
private final Car car = new Car();
private final Job job = new Job("none");
private final House hosue = new House();
public void makeHouseWooden() { //the method exists here in player class
house.setMode(wooden);
house.incrementTimesEdited(1);
house.refreshIfInside();
house.configureNewEnvironment();
}
}
This is what I've been seeing on other projects and would like to follow as the player class gets pretty big with methods:
#Data //lombok for setters/getters
public final class Player implements ContentWorker {
private final Car car = new Car();
private final Job job = new Job("none");
private final House hosue = new House();
#Override
public Player player() {
return this;
}
}
and the interface handles methods relating to the fields in Player.java
public interface ContentWorker {
Player player();
public default void makeHouseWooden() {
House house = player().getHouse();
house.setMode(wooden);
house.incrementTimesEdited(1);
house.refreshIfInside();
house.configureNewEnvironment();
}
}
I want to change to the second model because if I continue as I am at the moment then the Player class will become huge. (over 3000 lines)
This way I can keep the Player class for the fields only (better readability) and I could also have an interface which handles all house methods, another which handles all car methods and another which handles all job methods. (to avoid huge unreadable classes, also more dynamic interaction, easier to find the method you want)
public final class Player implements HouseWorker, CarWorker, JobWorker {
Which is better or more "efficient" and "easy to use" for my predicament?
In an android game i am writing, i have my code organized as follows:
I have a World object, that contains many Area objects. Inside each Area object are Place objects. These are arranged in multidimensional arrays that make it easy for the player to move around in.
I also have Player and Inventory objects that i use as constructors for my World object so that ican access the Player/Inventory and make changes to it as necessary (ex: add "item" to inventory; player -10 health).
public class World
Player player;
Inventory inventory;
public World(Player player, Inventory inventory){
this.player=player;
this.inventory=inventory;
}
public Player returnPlayer(){
return player;
}
public Inventory returnInventory(){
return inventory;
}
to create an Area: i use a World object as a constructor
public class StartingArea extends Area
Player player;
Inventory inventory;
World world;
public StartingArea(World world){
this.world=world;
player=world.returnPlayer;
inventory=world.returnInventory;
}
I also have returnPlayer and returnInventory methods within my Area objects.
And when i create my Place objects within my Area objects, i use an Area as a constructor":
House house = new house(this);
public class House extends Place
Player player;
Inventory inventory;
public House(Area area){
inventory=area.returnInventory;
player=area.returnPlayer
}
however, by the time i pass down these player and inventory objects that i created back when i created my world object, something gets messed up. I am unable to access the inventory object, and my app force closes. I tried making my world instance static:
Player player = new Player();
Inventory inventory = new Inventory();
public static World world;
world = new world(player,inventory);
and when it is static, i can successfully alter the inventory object
by referring to:
MainActivity.world.returnInventory().add(item) //add(Item item) is a method in inventory
So, something that I do not quite understand is going on here. Perhaps it is a problem with inheritance (extends)? Or maybe the way i am passing down objects is illegal or improper? I have just started to learn java, so this could be a simple fix or conceptual thing that I missing.
I would like to avoid creating a static instance of my World object because i am not sure how this will affect supporting multiple save files in my game.
If you have just one player and one inventory you could use singletons to be able to get access to them anywhere. Something like this.
public class Player {
private static Player sPlayer;
// variables etc
public static Player getInstance() {
if (sPlayer == null) {
sPlayer = new Player();
}
return sPlayer;
}
// methods etc
}
public class Inventory {
private static Inventory sInventory;
// variables etc
public static Inventory getInstance() {
if (sInventory == null) {
sInventory = new Inventory();
}
return sInventory;
}
// methods etc
}
Then in other activities and classes you could get reference easily without passing them as parameters
public class StartingArea extends Area {
Player player;
Inventory inventory;
World world;
public StartingArea(World world){
this.world=world;
player=Player.getInstance();
inventory=Inventory.getInstance();
}
}
I'm kinda new to Java, so I have a, rather dumb, question: Is it possible to have and use subclass'es objects in superclass which too have a constructor?
Here's an example what I want to do: I have Superclass Team and subclass Player. I want to create Player object, which contains variables like name, surname, height, etc. . And I want to access this Player object in Team class, which have it's name, positions and other variables, to assign the Player object to his position in the Team. Lets say, Player: John Doe is in Team named Red and he is a Goalkeeper.
And all together, is it possible to access all of this in main function? For example I want to print out all Team Red's players names.
Sorry, it's kinda complicated to explain what I want to do, but isn't this have to do something with extends?
The short answer is that yes, this is possible.
The longer answer is that you're misusing the terms superclass and subclass. The relationship you describe is not an is-a relationship of inheritance, but a has-a relationship of composition.
In other words, your Player class does not extend your Team class. Your Team class would contain instances of Player. And yes, in that case your Team class could access the methods and variables of those instances, just like you can any other Java class. It might look something like this:
class Team{
List<Player> players = new ArrayList<Player>();
public void addPlayer(Player p, String position){
p.position = position;
players.add(p);
}
}
And then from a main() method, you might do something like this:
public class Main{
public static void main(String... args){
Team team = new Team("Fighting Cats");
Player p = new Player("Johnny Appleseed");
team.addPlayer(p, "Apple Picker");
}
}
Yes, see the below code.
public class Team{
public Player player;
}
class Player extends Team{
public Team team;
}
Although, I doubt your logic and design when you say that Player extends Team, which essentially says that a Player is a Team. This would mean that each Player object would have a list of players and positions (as subtypes inherit non-private states and behaviours from supertypes), which doesn't make much sense semantically.
I suggest that you instead approach it like the following.
public class Team{
public LinkedList<Player> players;
}
class Player{
public Position position; // Use some way of defining the player's position.
}
This means that Team would have a Player, rather Player being a Team
What you are looking for is a composition and not inheritance (i.e. A Team "has a" Player. "A Player is a Team" does not make much sense)
class Player {
String name;
String surname;
String height;
}
class Team {
String name;
List<Player> players;
}
You have to create 3 classes Team, Player & a Client class to input the data.
I am writing the skeleton code for you. It will give you an idea as to how to write your code
public class Team {
ArrayList<Player> player;
public ArrayList<Player> getPlayer() {
return player;
}
public void setPlayer(ArrayList<Player> player) {
this.player = player;
}
}
Player
class Player{
String name;
Integer score;
Integer Rank;
//getter setters
}
Client class
public class Client {
public static void main(String[] args) {
Player pOne = new Player();
pOne.setRank(2);
pOne.setName("ABD");
Player pTwo=new Player();
pTwo.setRank(2);
pTwo.setName("SPC");
pTwo.setTotal(60);
ArrayList<Player> playerList = new ArrayList<Player>();
playerList.add(pOne);
playerList.add(pTwo);
Team team=new Team();
one.setPlayer(playerListOne);
//get the player using Team class's getPlayer method & print
}
You need not use extends but rather focus on the OO design.
When we think about team and player, its relation is team has a player.
Use the same relation when you design the classes.
Position is a property which is relevant in the scope of a Player. So introduce that property in correct level. Better to keep Team class with its own properties.
I am never quite sure that I am using static methods correctly. I understand how they work.
Let's say I have this class called Player(Java):
private int money;
private int lot;
private String piece;
private int playerNum;
public Player(String _piece, int _playerNum)
{
piece = _piece;
lot = 0;
playerNum = _playerNum;
money = 20000;
}
public int getMoney()
{
return money;
}
public int getLot()
{
return lot;
}
public String getPiece()
{
return piece;
}
There are some other methods + setters, but they are specific to the player object I create, now let's say I have a static method like this:
private static int numOfPlayers;
public static int numPlayers()
{
return numOfPlayers;
}
Where should this numOfPlayers method be placed?
Should it be put in my Player class? And should I increment the numOfPlayers varible everytime a new isntance of the player object is created?(via the constructor)
Or, should I have I have the method in my Game class as non-static and just call the method everytime I create a new Player.
Static fields and methods are supposed to represent stateless attributes of a class; i.e. not pertinent to a particular object.
But be careful with multithreading with statics since the whole class has to be locked rather than just one object. This can lead to concurrency bottlenecks.
As for your numOfPlayers, you'll probably end up having a collection of players developed somewhere else, in which case that function will be a method on that collection not in the player class.
Ideally, in my opinion at least, an individual player should not really be concerned about the players collection. Therefore a static function such as the one you propose would not be good design.
It is a matter of design, which obviously includes a lot of personal preference.
You really should have a look at the factory design pattern, which is a good way of handling such cases. Here, you could have a
public class PlayerFactory {
private int numPlayers = 0;
public int getNumPlayers() { ... }
public Player makeNewPlayer(...) { ... }
}
that takes care of A) incrementing the player count appropriately.
Depending on your exact use case and code style, you may prefer one variation or another. But it is good to know these patterns and recognize them. And document them. By calling a class SomethingFactory you do hint for other developers that this class follows the factory pattern, for example.
Note that I did not need to use static in above example, assuming that the factory may only be instantiated once. It is common to see the constructor private and instead the class then has a public static final instance only.
You could also call this class Game or Players...
how about you have a List of Players in your game and the number of players is the size of the List.
When you think you should use static for some functionality, don't do it!
Just play along the old rule to never use anything static until you are old and wise and where you perhaps can use it for some very special corner case.
You can create it like this:
Have class Player like you have
Create class Players
class Players
{
private List<Player> players = new List<Players>;
public void AddPlayer(Player pl)
{
this.players.add(pl);
}
public int GetPlayersCount()
{
return this.players.size();
}
}
If you want, you can make this class "static" using Singleton. But try to avoid static classes.
class Players
{
private List<Player> players = new List<Players>;
private static Players instance;
private Players () {};
public static Players getInstance()
{
if (instance == null)
{
instance = new Players ();
}
return instance;
}
public void AddPlayer(Player pl)
{
this.players.add(pl);
}
public int GetPlayersCount()
{
return this.players.size();
}
}
And use it like this
Players players = Players.getInstance();
players.AddPlayer(....)
I would have the list of Players in another class, e.g. Game as you suggested.
Something like
class Game {
private final List<Player> players = new ArrayList<Player>();
public int getNumOfPlayers() {
return players.size();
}
public void addPlayer(final Player player) {
players.add(player);
}
...
You add a player via your instance of Game, game via game.addPlayer(newPlayer), and get the number of players via game.getNumOfPlayers().
The List of players is dynamically allocated.
As for static or not static, I prefer here the non static version, as the players are part of a Game, and one could consider they may be several games - and players would be part of an instance of Game.