I just started learning Guice, but I've already encountered a problem. I have an interface PlayerFactory with one implementation BlackjackPlayer
PlayerFactory.java
public interface PlayerFactory {
Player createPlayer(String name);
Player createPlayer(String name, boolean isDealer);
}
BlackjackPlayer.java
public class BlackjackPlayer implements PlayerFactory {
private PointsCalculator pointsCalculator;
public BlackjackPlayer(){
pointsCalculator = new BlackjackPointsCalculator();
}
#Override
public Player createPlayer(String name) {
return new Player(pointsCalculator, name);
}
#Override
public Player createPlayer(String name, boolean isDealer) {
return new Player(pointsCalculator, name, isDealer);
}
}
Player.class
public class Player{
private PointsCalculator pointsCalculator;
private List<Card> cardsInHand;
private Integer points;
private String name;
private boolean isDealer;
private boolean endedTurn;
#AssistedInject
public Player(PointsCalculator blackjackPointsCalculator, String name){
pointsCalculator = blackjackPointsCalculator;
cardsInHand = new ArrayList<>();
points = 0;
this.name = name;
isDealer = false;
endedTurn = false;
}
#AssistedInject
public Player(PointsCalculator blackjackPointsCalculator, String name, boolean isDealer){
pointsCalculator = blackjackPointsCalculator;
cardsInHand = new ArrayList<>();
points = 0;
this.name = name;
this.isDealer = isDealer;
endedTurn = false;
}
public void addCardToHand(Card card) {
cardsInHand.add(card);
updatePoints();
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Player)) return false;
Player player = (Player) o;
return getPoints() == player.getPoints() &&
isDealer() == player.isDealer() &&
isEndedTurn() == player.isEndedTurn() &&
Objects.equals(pointsCalculator, player.pointsCalculator) &&
Objects.equals(getCardsInHand(), player.getCardsInHand()) &&
Objects.equals(getName(), player.getName());
}
#Override
public int hashCode() {
return Objects.hash(pointsCalculator, getCardsInHand(), getPoints(), getName(), isDealer(), isEndedTurn());
}
public void updatePoints() {
points = pointsCalculator.calculatePoints(cardsInHand);
}
public List<Card> getCardsInHand(){
return cardsInHand;
}
public Integer getPoints(){
return points;
}
public String getName(){
return name;
}
public boolean isDealer() {
return isDealer;
}
public boolean isEndedTurn() {
return endedTurn;
}
public void setName(String name){
this.name = name;
}
public void setDealer(boolean isDealer){
this.isDealer = isDealer;
}
public void setEndedTurn(boolean endedTurn){
this.endedTurn = endedTurn;
}
}
I want to use Guice assisted inject to create Player. Previously I did it as follows:
install(new FactoryModuleBuilder().build(PlayerFactory.class));
which I know is wrong way, because I receive error message:
1) com.github.blackjack.model.Player has #AssistedInject constructors, but none of them match the parameters in method com.github.blackjack.factory.PlayerFactory.createPlayer(). Unable to create AssistedInject factory.
while locating com.github.blackjack.model.Player
at com.github.blackjack.factory.PlayerFactory.createPlayer(PlayerFactory.java:1)
2) com.github.blackjack.model.Player has #AssistedInject constructors, but none of them match the parameters in method com.github.blackjack.factory.PlayerFactory.createPlayer(). Unable to create AssistedInject factory.
while locating com.github.blackjack.model.Player
at com.github.blackjack.factory.PlayerFactory.createPlayer(PlayerFactory.java:1)
I tried to add constructors Player(String name), Player(String name, boolean isDealer) but it didn't help. Does someone know what should I do to fix the problem?
Thanks in advance!
You need to use the #Assisted annotation on the injectee parameters:
PlayerFactory.java
public interface PlayerFactory {
Player createPlayer(String name);
Player createPlayer(String name, boolean isDealer);
}
BlackjackPlayer.java (Change it from a factory to the actual player)
public class BlackjackPlayer implements Player {
private final PointCalculator pointsCalculator;
private final String name;
private final boolean isDealer;
#AssistedInject BlackjackPlayer(PointCalculator pointsCalculator, #Assisted String name) {
this.pointsCalculator = pointsCalculator;
this.name = name;
this.isDealer = false;
}
#AssistedInject BlackjackPlayer(PointCalculator pointsCalculator, #Assisted String name, #Assisted boolean isDealer) {
this.pointsCalculator = pointsCalculator;
this.name = name;
this.isDealer = isDealer;
}
}
And use the module as the following:
install(new FactoryModuleBuilder()
.implement(Player.class, BlackjackPlayer.class)
.build(PlayerFactory.class)
);
Related
This is a generic class with bound type Player.
public class Team<T extends Player> implements Comparable<Team<T>> {
private String name;
private int played=0;
private int won=0;
private int lost=0;
private int tide=0;
private ArrayList<T> members = new ArrayList<>();
public Team(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getWon() {
return won;
}
public boolean addPlayer(T player){
if(members.contains(player)){
System.out.println(player.getName() + " is already on this team" );
return false;
}else{
members.add(player);
System.out.println(player.getName()+" picked for team "+this.name);
return true;
}
}
public int numPlayer(){
return this.members.size();
}
}
This is a generic class with bound Type as Team.
public class League<T extends Team>{
public String name;
private ArrayList<T> league = new ArrayList<>();
public League(String name) {
this.name = name;
}
public boolean addTeam(T team){
if(league.contains(team)){
System.out.println("It is already exist");
return false;
}else{
league.add(team);
return true;
}
}
public void showLeagueTable(){
Collections.sort(league);
for(T t:league){
System.out.println(t.getName()+" : "+t.ranking());
}
}
}
I don't know how to create an object for the League class, literally not able to figure out how to mention type. I've tried several ways, but none of them worked for me. Could you guys help me with this code?
I am getting a Exception in Thread main
java.lang.NoSuchMethodException: com.laurens.Main.main([Ljava.lang.String;)
at java.lang.Class.getMethod(Class.java:1786)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:125)
Can someone explain where I am going wrong here?
Main
package com.laurens;
public class Main {
private player player;
public Main(com.laurens.player player) {
this.player = player;
}
public com.laurens.player getPlayer() {
return player;
}
public void setPlayer (int performance, String name) {
if (performance < 4) {
boolean injured = true;
}
}
#Override
public String toString() {
return "com.laurens.Main{" +
"player=" + player +
'}';
}
}
player
package com.laurens;
/**
* Created by laurensvanoorschot on 20-01-16.
*/
public class player {
private String name;
private int performance;
private boolean injured;
public player(int performance, boolean injured, String name) {
this.injured = injured;
this.name = name;
this.performance = performance;
}
public boolean isInjured() {
return injured;
}
public void setInjured(boolean injured) {
this.injured = injured;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPerformance() {
return performance;
}
public void setPerformance(int performance) {
this.performance = performance;
}
}
You don't have a method called main, which is what it is looking for to run your program. Notice that when you create a template application for a java console application in intelliJ it has a method:
public static void main(string[] args) {
}
That needs to be there for your program to run.
The following class keeps giving me a null pointer when I try to call the addPlayer method and I have no idea what the heck I'm doing wrong. : Keep in mind this is really simple stuff...supposedly... I'm learning Java.
import java.util.*;
public class Team {
private String teamName;
private ArrayList<Player> players;
private int numberOfPlayers;
public Team(String teamName) {
this.teamName = teamName;
}
public String getName() {
return this.teamName;
}
public void addPlayer(Player player) {
this.players.add(player);
}
public void printPlayers() {
for (Player player : this.players) {
System.out.println(player);
}
}
}
Here is the Player class :
public class Player {
private String name;
private int goals;
public Player(String name) {
this.name = name;
}
public Player(String name, int goals) {
this.name = name;
this.goals = goals;
}
#Override
public String toString() {
return this.getName() + ", goals " + this.goals();
}
public String getName () {
return this.name;
}
public int goals() {
return this.goals;
}
}
This is your problem:
private ArrayList<Player> players;
is not initialized, you never create a new one when you instantiate your class.
Add the following to your constructor:
public Team(String teamName) {
this.teamName = teamName;
this.players = new ArrayList<Player>();
}
You haven't initialized the variable, thus its value is null.
private ArrayList<Player> players = new ArrayList<Player>();
That should fix it.
You have declared an ArrayList but where is the initialization??
Fix it by initializing the ArrayList as :
private ArrayList<Player> players = new ArrayList<Player>();
I'm making a little game with a hero having inventory filled with object.
public enum Objects_type
{
WEAPON,
ARMOR
}
public abstract class Objects_class
{
protected String name;
protected Objects_type type;
public Objects_class(String name, Objects_type type)
{
this.name = name;
this.type = type;
}
}
public abstract class Armor extends Objects_class{
int life = 0;
int res_fire = 0;
public Armor(String name, int largeur, int hauteur) {
super(name, Objects_type.ARMOR);
}
}
public abstract class Weapon extends Objects_class
{
protected int dmg_fire = 0;
public Weapon(String name) {
super(name, Objects_type.WEAPON);
}
}
public class StickOfJoy extends Weapon{
public StickOfJoy() {
super("Stick of Joy");
dmg_fire = 2;
}
}
public class ArmorOfPity extends Armor{
public ArmorOfPity()
{
super("Armor of Pity");
life = 30;
}
}
Then I have functions like :
Hero.getObject (Objects_class obj)
{
if (obj.getType == Objects_type.WEAPON)
....
}
I'd like to be able to consider the Objects_class obj as a Weapon but of course it's not possible (casting a mother to its child) so it makes me think my inheritance structure is bad.
What should I've done ?
David Conrad has some good points I recommend you read through that I won't repeat here but here is how I would do it.
Suppose you have a character that is roaming around in your game world picking up items, there can be many different items, some so different from each other in behavior they warrant the creation of a new subclass (like picking up boots vs picking up wings).
Once you pick up an item, you have the choice of letting the hero try and see what kind of item was picked up (instanceof, enums, whatever) or you can let the item figure out where it is supposed to go.
Here is a simplified example where the player has only two inventory slots, a weapon and an armor. Notice how easy it is to simply add a new item (like a health potion, or a superdupernewspecialweapon) to the mix without having to change anything in the player or do casting.
public abstract class Item {
private int ID;
private static int IDCounter;
private String name;
public Item(String name) {
this.name = name;
this.ID = IDCounter;
IDCounter++;
}
public int getID() {
return ID;
}
public String getName() {
return name;
}
public abstract void attachToPlayer(Player player);
}
public class Armor extends Item {
private int life;
private int res_fire;
public Armor(String name) {
super(name);
}
#Override
public void attachToPlayer(Player player) {
// Only equip if upgrade
if (player.getArmor().res_fire > this.res_fire)
player.setArmor(this);
}
}
public class Weapon extends Item {
private int dmg_fire;
public Weapon(String name) {
super(name);
}
// ...stuff
#Override
public void attachToPlayer(Player player) {
// Only equip this if upgrade? You decide the logic
if(player.getWeapon().dmg_fire>this.dmg_fire)
player.setWeapon(this);
}
}
public class SuperSpecialWeapon extends Weapon {
private float bonusHealthModifier = 1.0f;
public SuperSpecialWeapon(String name) {
super(name);
}
#Override
public void attachToPlayer(Player player) {
// This bonus adds +100%HP bonus to the player!
int hp = (int) ((1 + bonusHealthModifier) * player.getHealth());
player.setHealth(hp);
player.setWeapon(this);
}
}
public class Potion extends Item {
private int health = 100;
public Potion() {
super("HealthPotion");
}
#Override
public void attachToPlayer(Player player) {
// If the player has room for one more potion, pick this up
Potion[] potions = player.getHealthPotions();
for (int i = 0; i < potions.length; i++) {
if(potions[i]==null){
potions[i] = this;
break;
}
}
}
// ..other stuff
}
And finally the player
public class Player {
private Armor armor;
private Weapon weapon;
private String name;
private Potion[] healthPotions = new Potion[10];
private int health;
public Player(String name) {
this.name = name;
}
public Armor getArmor() {
return armor;
}
public Weapon getWeapon() {
return weapon;
}
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
public void setArmor(Armor armor) {
this.armor = armor;
}
public void setHealth(int health) {
this.health = health;
}
public int getHealth() {
return health;
}
public Potion[] getHealthPotions() {
return healthPotions;
}
}
There is no need of Objects_type, since objects in Java know what type they are, and their type can be tested with the instanceof operator. You say that you cannot cast "a mother to its child", but it is possible to downcast an object to a child type. In general, it could throw a ClassCastException, but if you have tested it first with instanceof, that won't happen.
public class Objects_class {
protected String name;
public Objects_class(String name) {
this.name = name;
}
}
public class Armor extends Objects_class {
int life = 0;
int res_fire = 0;
public Armor(String name, int largeur, int hauteur) {
super(name);
}
}
public class Weapon extends Objects_class {
protected int dmg_fire = 0;
public Weapon(String name) {
super(name);
}
}
public class Hero {
public void getObject(Objects_class obj) {
if (obj instanceof Weapon) {
Weapon weapon = (Weapon) obj;
wield(weapon);
}
if (obj instanceof Armor) {
Armor armor = (Armor) obj;
wear(armor);
}
}
}
I have removed the abstract modifier from the classes since there is no need of it, but perhaps you wanted it to ensure that those base classes are never instantiated. Also, I would change the name of Objects_class to something like Item since the words Object and class have particular meanings that could cause confusion. I would also rename Hero's getObject method to something like pickUpItem since it isn't a getter, in the Java sense.
How to solve the following constructor overloading problem? This is an interview question but I am curious to know the solution.
class Player
{
int nationalRank;
int internationalRank;
String name;
Player(String name, int nationalRank)
{
this.name= name;
this.nationalRank = nationalRank;
this.internationalRank=0;
}
Player(String name, int internationalRank)
{
this.name= name;
this.nationalRank = 0;
this.internationalRank=internationalRank;
}
}
Here, the compiler will give an error because argument types are same for both constructor. But logically they both are different. How can I solve this problem without adding any extra arguments? Is there any design pattern specifically for this?
class Player
{
int nationalRank;
int internationalRank;
String name;
private Player(){}
public static Builder builder()
{
return new Builder();
}
public static class Builder
{
int nationalRank = -1;
int internationalRank = -1;
String name;
public Builder nationalRank(int nationalRank)
{
this.nationalRank = nationalRank;
return this;
}
public Builder internationalRank(int internationalRank)
{
this.internationalRank = internationalRank;
return this;
}
public Builder name(String name)
{
this.name = name;
return this;
}
public Player build()
{
if (nationalRank == -1 && internationalRank = -1)
throw new IllegalStateException("both ranks haven't been initialized");
if (null == name)
throw new IllegalStateException("name hasn't been initialized");
Player result = new Player();
result.nationalRank = this.nationalRank;
result.internationalRank = this.internationalRank;
result.name = this.name;
return result;
}
}
}
Usage:
Player player = Player.builder().name("John").internationalRank(522).build();
You've got various options.
The simplest is to add factory methods like this:
public class Player
{
private int nationalRank;
private int internationalRank;
private String name;
private Player()
{
}
public static Player newNationalPlayer(String name, int nationalRank)
{
Player nationalPlayer = new Player();
nationalPlayer.name= name;
nationalPlayer.nationalRank = nationalRank;
nationalPlayer.internationalRank = 0;
return nationalPlayer;
}
public static Player newInternationalPlayer(String name, int internationalRank)
{
Player internationalPlayer = new Player();
internationalPlayer.name= name;
internationalPlayer.nationalRank = 0;
internationalPlayer.internationalRank = internationalRank;
return internationalPlayer;
}
...
}
However, this leaves an unused variable which isn't very nice. A better solution would be to add a PlayerType enum:
public enum PlayerType
{
NATIONAL,
INTERNATIONAL
}
public class Player
{
private int rank;
private String name;
private PlayerType type;
public Player(String name, PlayerType type, int rank)
{
this.name= name;
this.type = type;
this.rank = rank;
}
...
}
Which is best is down to the exact use case.
Just reverse the parameters of one of the constructors and you are good to go.... I made this answer thinking that it's an interview question....perhaps the interviewer has this in mind...
class Player
{
int nationalRank;
int internationalRank;
String name;
Player(String name, int nationalRank)
{
this.name= name;
this.nationalRank = nationalRank;
this.internationalRank=0;
}
Player( int internationalRank,String name)
{
this.name= name;
this.nationalRank = 0;
this.internationalRank=internationalRank;
}
}
As suggested by a comment, just use static factory methods. In fact, this solution goes further than that and uses a builder. You will note a clear advantage: all instance variables are now final.
public class Player
{
private final String name;
private final int nationalRank;
private final int internationalRank;
// Constructor becomes private
private Player(final Builder builder)
{
name = builder.name;
nationalRank = builder.nationalRank;
internationalRank = builder.internationalRank;
}
public static Builder withName(final String name)
{
return new Builder(name);
}
// Inner builder class
public static class Builder
{
private final String name;
private int nationalRank;
private int internationalRank;
private Builder(final String name)
{
this.name = name;
}
public Builder withNationalRank(int rank)
{
nationalRank = rank;
return this;
}
public Builder withInternationalRank(int rank)
{
internationationalRank = rank;
return this;
}
public Player build()
{
return new Player(this);
}
}
}
Usage:
Player player1 = Player.withName("foo").withNationalRank(1).build();
// etc