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
Related
i'm writing a function to create xls sheets from JFXTableView.
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet("user details");
XSSFRow header = sheet.createRow(0);
String arrayOfHeaders [] = {"Sr. No.","Name of the Member", "Customized workout card status","Contact No.","Current programme taken","Current package taken",
"Purpose of taking customized workout card", "body type identified"," Current Body weight","Current height","payment amount",
"Mode of payment"};
for(int i=0; i<arrayOfHeaders.length; i++){
header.createCell(i).setCellValue(arrayOfHeaders[i]);
}
int index=1;
for(Member item: tableView.getItems()){
XSSFRow row = sheet.createRow(index);
int cellIndex=0;
for (Method m : item.getClass().getMethods()) {
// The getter should start with "get"
// I ignore getClass() method because it never returns null
if (m.getName().startsWith("get") && !m.getName().equals("getClass")) {
row.createCell(cellIndex).setCellValue((String) m.invoke(item));
}
cellIndex++;
}
index++;
}
With the above code, i'm able to retrieve values from the table through the getters, but the problems is item.getClass().getMethods() returns getters in a random order and that is not acceptable as i want the values according to the headers as defined.
I have many such tables, each with their own Class and getters, and writing different functions for each one of them seems too lengthy. So, what i'm planning to do is write a function where i could pass on the getters of each different table object in an array, so it could loop through all the getters of the particular tableView object. Something like this:
createSheets(arrayOfHeaders, tableView.getItems(), arrayOfGetters);
The example of one such Member Class being used by my current tableView is:
public static class Member{
private final SimpleStringProperty name;
private final SimpleStringProperty status;
private final SimpleStringProperty contact;
private final SimpleStringProperty programme;
private final SimpleStringProperty packages;
private final SimpleStringProperty purpose;
private final SimpleStringProperty bodyType;
private final SimpleStringProperty weight;
private final SimpleStringProperty height;
private final SimpleIntegerProperty paymentAmount;
private final SimpleStringProperty paymentMode;
public Member (String name, String status, String contact, String programme, String packages, String purpose,
String bodyType, String weight, String height, int paymentAmount, String paymentMode){
this.name = new SimpleStringProperty(name);
this.status = new SimpleStringProperty(status);
this.contact = new SimpleStringProperty(contact);
this.programme = new SimpleStringProperty(programme);
this.packages = new SimpleStringProperty(packages);
this.purpose = new SimpleStringProperty(purpose);
this.bodyType = new SimpleStringProperty(bodyType);
this.weight = new SimpleStringProperty(weight);
this.height = new SimpleStringProperty(height);
this.paymentAmount = new SimpleIntegerProperty(paymentAmount);
this.paymentMode = new SimpleStringProperty(paymentMode);
}
public String getName() {
return name.get();
}
public String getStatus() {
return status.get();
}
public String getContact() {
return contact.get();
}
public String getProgramme() {
return programme.get();
}
public String getPackages() {
return packages.get();
}
public String getPurpose() {
return purpose.get();
}
public String getBodyType() {
return bodyType.get();
}
public String getWeight() {
return weight.get();
}
public String getHeight() {
return height.get();
}
public int getPaymentAmount() {
return paymentAmount.get();
}
public String getPaymentMode() {
return paymentMode.get();
}
}
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)
);
I am making a text-based game on JavaFX, and after I hit a tree, I want to get Oak logs.
I have already built my inventory, and I have put default items in it such as Water, Bread, etc.
I am trying to add my Oak Logs to my inventory, but nothing is working.
Here is a part of my code:
Item ItemList[] = {new Bread(), new OakLog()};
Optional<ButtonType> result = alert.showAndWait();
if(result.get() == buttonTypeOak) {
woodcuttingXP = woodcuttingXP + oakXP;
dialogue.appendText("You swing at an Oak tree. + " + oakXP + "XP.\n");
dialogue.appendText("You gathered 1 log.\n");
mainCharacter.getInventory().add(new OakLog());
}
Here is my Item Class:
package game;
public class Item {
private String name;
private int weight;
private int quantity;
private int value;
private String description;
public Item(String name, int value, String description) {
this.name = name;
this.value = value;
this.description = description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String toString() {
return getName();
}
}
And finally, here is my Character class:
package game;
import java.util.ArrayList;
import beverages.Water;
import items.OakLog;
import rawFood.Bread;
public class Character {
private String name;
private int hydrationLevel;
private int healthLevel;
private int hungerLevel;
private int woodcuttingLevel;
public int getWoodcuttingLevel() {
return woodcuttingLevel;
}
public void setWoodcuttingLevel(int woodcuttingLevel) {
this.woodcuttingLevel = woodcuttingLevel;
}
public int getHungerLevel() {
return hungerLevel;
}
public void setHungerLevel(int hungerLevel) {
this.hungerLevel = hungerLevel;
}
private ArrayList<Item> inventory = new ArrayList<Item>();
public ArrayList<Item> getInventory() {
return inventory;
}
public void setInventory(ArrayList<Item> inventory) {
this.inventory = inventory;
}
//creates a person with two basic items
public Character(String name){
this.name = name;
this.hydrationLevel = 100;
this.healthLevel = 100;
this.hungerLevel = 100;
this.woodcuttingLevel = 1;
addToInventory (new Bread());
addToInventory (new OakLog());
addToInventory (new Water());
}
//GETTERS AND SETTERS
public String getName() {
return name;
}
public int getHydrationLevel() {
return hydrationLevel;
}
public void setHydrationLevel(int hydrationLevel) {
this.hydrationLevel = hydrationLevel;
}
public int getHealthLevel() {
return healthLevel;
}
public void setHealthLevel(int healthLevel) {
this.healthLevel = healthLevel;
}
//END GETTERS AND SETTERS
/*Method Name: eat()
*Method Inputs: a piece of food
*Method Purpose: Will allow the user to eat food
*/
public Item getItemFromInventory(int index){
Item item = inventory.get(index);
return item;
}
public void addToInventory(Item item){
if(inventory.contains(item)){
item.setQuantity(item.getQuantity()+1);
}
else{
item.setQuantity(1);
inventory.add(item);
}
}
public String toString(){
return "Character Stats:\nName:" + getName() + "\nHydration: " + getHydrationLevel() + "\nHealth: " + getHealthLevel() + "\nWoodcutting: " + getWoodcuttingLevel();
}
}
In your code, you have:
if(inventory.contains(item)){
item.setQuantity(item.getQuantity()+1);
}
This just updates the quantity of the local variable item in the method, not the item in the inventory.
I am creating the ArrayList of Object, to insert information I use different constructors in that class but I have one type variable that I update with every constructor call. here is what i am doing
public class eProperty {
public String type = null;
public int marks;
public int code;
public String category
public String student_name = null;
public String employee_name = null;
public String o_name = null;
public eProperty(String type, String student_name, int marks) {
this.marks = marks;
this.type = type;
this.student_name = student_marks;
}
public eProperty(String type, String employee_name, int makrs, String category) {
this.marks = marks;
this.type = type;
this.employee_name = employee_name;
this.category = category;
}
public eProperty(String type, int code, int makrs, String o_name) {
this.marks = marks;
this.type = type;
this.mnc = code;
this.o_name = o_name;
}
}
I populate arraylist like this,
ArrayList<eProperty> allData;
eProperty data;
if(type.equals("Student")) {
data = new eProperty(type, "John", 45)
allData.add(data)
}
if(type.equals("Employee")){
data = new eProperty(type, "Vicky", 86, "Developer")
allData.add(data)
} ... other cases also handled like this
Now I want to retrive highest marks for each type and I am stuck here, any help
Thanks
Using loop (sorry for that...) and Predicate from Apache Commons
public static int getHighestMarkByType(ArrayList<eProperty> allData, String type) {
Predicate predicate = new Predicate() {
public boolean evaluate(Object data) {
if ((eProperty) data).getType().equals(type)) {
return true;
} else {
return false;
}
}
};
ArrayList<eProperty> filteredData = (ArrayList<eProperty>) CollectionUtils.select(allData,predicate);
int maxMarks = 0;
for (eProperty data : filteredData) {
if (data.getMarks() > maxMark) {
maxMarks = data.getMark();
}
}
return maxMarks;
}
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>();