I'm writing a game-like program and it has a class that has to act as an item. Normally I would just keep it as an item but every one has to wait 10 game-days in order to start doing what it's meant to. Is there a way to update the days in all the classes at once? I've tried to use a static method but you can't use instance variables in those so it didn't work. I've thought about possibly making a code that expands every time a new instance is made but I can't find anything i can understand about it. Is there any way to add to a method, make this an item, anything? This is what I have at the moment:
public class Tree
{
private boolean fullGrown;
private int day;
private int APDay; //apples per day
private static int totalApples;
public Tree()
{
fullGrown = false;
day = 0;
APDay = (int) (Math.random()*2) + 4;
}
public void updateDay()
{
day = day + 1;
if (day == 10) fullGrown = true;
if (fullGrown == true) totalApples = totalApples + APDay;
}
public void skipGrowth()
{
fullGrown = true;
}
}
Although this works, you have to update the day for every instance separately. I need a way to update all the instances at the same time. This will also be used by a code and not the actual interface, just in case that's helpful.
Observer and factory pattern looks like a good candidate here.
I hope the code below explain rest to you
public interface DayEventListener {
public void onDay10(DayEvent DayEvent);
}
public class DayEvent {
//... pojo
}
public class AwesomeGame {
private List<DayEventListener> dayEventListenerList = new ArrayList<>();
public void addDayListener(DayEventListener del) {
dayEventListener.add(del);
}
public void fireDay10Event(DayEvent de) {
for(DayEventListener del : dayEventListenerList) {
del.onDay10(de);
}
}
public class Item implements DayEventListener {
//All constructors should be private
public static Item buildItem() {
Item Item = new Item();
awesomeGame.addDayEventListener(Item);
return item;
}
}
so I did some research and while I was working on another project I discovered that i could use a vector to keep track of all my instances, so here is that class:
import java.util.Vector;
public class catcher
{
private static Vector allInstances = new Vector();
private int catchLeft;
private String name;
public catcher(String name)
{
catchLeft = Integer.parseInt(name.substring(name.indexOf("#") + 1, name.length()));
catchLeft--;
this.name = name;
if (catchLeft != 0) allInstances.add(this);
}
public static synchronized Vector getAllInstances()
{
return (Vector) (allInstances.clone());
}
public boolean check(String name, boolean change)
{
boolean foo;
if (this.name.equals(name))
{
if (change == true) catchLeft--;
foo = true;
}
else foo = false;
if (catchLeft <= 0) this.finalize();
return foo;
}
public void finalize()
{
allInstances.removeElement(this);
}
public static void clear()
{
allInstances.clear();
}
}
now that I have a record of all the instances, I used this method in another class to assess all the instances:
import java.util.Iterator;
import java.util.Vector;
public class recipe
{
private boolean checkForList(String name, boolean add)
{
Iterator list = catcher.getAllInstances().iterator();
boolean running = true;
boolean booleanReturn = true;
while (running == true)
{
if (list.hasNext())
{
catcher Foo = (catcher) (list.next());
if (Foo.check(name, false) == true)
{
Foo.check(name, true);
running = false;
booleanReturn = true;
}
}
else
{
if (add == true) new catcher(name);
running = false;
booleanReturn = false;
}
}
return booleanReturn;
}
}
I'm sure that this can be modified to update the classes instead of just accessing them.
Related
In my scenario, we offer multiple plans to customers. (planA, planB, planC etc.) planA is lower than planB and planB is lower than planC. A customer can move from lower plan to higher plan but not vice-versa. If a customer is on planA and wants to 'activate' planB, then planA must be cancelled. Essentially, a plan can be 'activated' and 'deactivated'. I had 2 designs in mind.
interface Plan {
activate();
deactivate();
}
This interface will be inherited by each plans' (planA, planB, planC, etc). The activate method would be inherited and look something like this:
activate() {
Plan planToCancel = getLowerGradePlanToCancel()
planToCancel.cancel();
// perform business logic to activate plan.
}
Option B is something similar to strategy pattern: I have 2 interfaces:
interface Activate {
activate();
}
interface Deactivate {
deactivate()
}
Each of the plans will inherit those interfaces. Then my business logic would look something like this:
activatePlan(planName, planToDeactivate) {
Activate activate = Factory.getActivateInstanceForPlan(planName);
DeActivate dectivate = Factory.getActivateInstanceForPlan(planToDeactivate);
deactivate.deactivate();
activate.activate();
}
Of the two designs which one is more appropriate (Object Oriented) and why ? The only thing in code that is likely to change is more plans will be added in future.
You have 3 plans. Plan C can't go higher and similarly plan A can't go lower. Plan B can do both operations. Use one interface and put activate and deactivate methods there. You already mentioned that on option A. Use template pattern there to give an opportunity to change their behaviours for your plans. This will be appropriate if you will add another plans later on. This will help you a lot when you add another plans.
If you will have only three plans, then second option is more appropriate. Since you have only 3 plans and only one of them using activate and deactivate together, then you don't need to implement both of the methods, interfaces. This will decrease the dependencies of your code.
Pick the best choice for your case.
I have a different approach in mind where you have a class that manages all the plans, while plan interface is encapsulated and only reveals the necessary of its API.
I think this approach will have minimal code modification for each added Plan, moreover, it can prevent user from making mistakes (e.g. downgrading a plan).
The essential interfaces:
interface Plan {
public Plan next();
public boolean isActivated();
// for debug purposes
public String planDescription();
}
interface PlansManager {
public Plan nextPlan(Plan current);
}
The basic idea is to have some SemiConcretePlan class which implements the static (mutual) behaviour in all plans, the public API is next & isActivated while activate and cancel methods private (you don't want the user to cancel a plan without switching to the next or to activated a cancelled one be keeping a previous Plan pointer on it) and only the PlansManager or the Plan itself will handle the activation and cancellation, PlansManager activates the first plan and returns it and next method uses PlansManager to get the next and only the SemiConcertePlan activate the current and cancels the previous Plan.
Here the SemiConcertePlan:
abstract class SemiConcretePlan implements Plan {
private PlansManager m_plansManager;
private boolean m_isActivated;
private int m_id;
private static int s_idGenerator = 0, s_firstActivatedId = 1;
public SemiConcretePlan(PlansManager plansManager){
m_plansManager = plansManager;
m_id = generateId();
m_isActivated = (m_id == s_firstActivatedId);
}
private int generateId() {
return ++s_idGenerator;
}
private void activatePlan() {
this.m_isActivated = true;
}
private void cancelPlan() {
this.m_isActivated = false;
}
public boolean isActivated() {
return this.m_isActivated;
}
public Plan next() {
this.cancelPlan();
SemiConcretePlan nextPlan = (SemiConcretePlan) m_plansManager.nextPlan(this);
nextPlan.activatePlan();
return nextPlan;
}
public boolean equals(Object other) {
if (this == other)
return true;
if (other == null || !(other instanceof SemiConcretePlan) || this.hashCode() != other.hashCode())
return false;
SemiConcretePlan otherPlan = ((SemiConcretePlan) other);
if (m_id != ((SemiConcretePlan) otherPlan).m_id)
return false;
return true;
}
public abstract int hashCode();
public abstract String planDescription();
}
planDescription method is an example of dynamic method, hashCode is needed for class PlansManager to hash plans in map which map current plan to higher (next) plan.
Here is the AscedingPlansManager class:
class AscedingPlansManager implements PlansManager{
private List<Plan> m_plansList;
private Map<Plan, Plan> m_planToHigherPlanMapping;
public AscedingPlansManager() {
m_plansList = new LinkedList();
m_planToHigherPlanMapping = new HashMap();
Plan[] plans = {
new PlanA(this),
new PlanB(this),
new PlanC(this),
new PlanD(this)
};
for(int i = 0; i < plans.length - 1; ++i) {
m_plansList.add(plans[i]);
m_planToHigherPlanMapping.put(plans[i], plans[i+1]);
}
m_plansList.add(plans[plans.length - 1]);
m_planToHigherPlanMapping.put(plans[plans.length - 1], plans[plans.length - 1]);
}
public Plan nextPlan(Plan current) {
return m_planToHigherPlanMapping.getOrDefault(current, null);
}
private void activatePlan(Plan plan) {
try {
Method privateActivateMethod = SemiConcretePlan.class.getDeclaredMethod("activatePlan");
privateActivateMethod.setAccessible(true);
privateActivateMethod.invoke(plan);
} catch(Exception e) {
e.printStackTrace();
}
}
public void cancelAll() {
for(Plan plan: m_plansList)
try {
Method privateActivateMethod = SemiConcretePlan.class.getDeclaredMethod("cancelPlan");
privateActivateMethod.setAccessible(true);
privateActivateMethod.invoke(plan);
} catch(Exception e) {
e.printStackTrace();
}
}
public Plan firstPlan() {
Plan first = m_plansList.get(0);
this.activatePlan(first);
return first;
}
public boolean[] plansToActivationState() {
boolean[] ret = new boolean[m_plansList.size()];
int index = 0;
for(Plan plan: m_plansList)
ret[index++] = plan.isActivated();
return ret;
}
}
I know that this is huge code, but I think it will make add plans easy, you will only need to change the hashCode method, the sequence of the plans can be changed in the constructor of AscedingPlansManager or creating a different manger class from scratch.
Here is the full code, you can see how little changes I needed to do for class PlanD:
import java.util.;
import java.lang.reflect.;
interface Plan {
public Plan next();
public boolean isActivated();
// for debug purposes
public String planDescription();
}
interface PlansManager {
public Plan nextPlan(Plan current);
}
abstract class SemiConcretePlan implements Plan {
private PlansManager m_plansManager;
private boolean m_isActivated;
private int m_id;
private static int s_idGenerator = 0, s_firstActivatedId = 1;
public SemiConcretePlan(PlansManager plansManager){
m_plansManager = plansManager;
m_id = generateId();
m_isActivated = (m_id == s_firstActivatedId);
}
private int generateId() {
return ++s_idGenerator;
}
private void activatePlan() {
this.m_isActivated = true;
}
private void cancelPlan() {
this.m_isActivated = false;
}
public boolean isActivated() {
return this.m_isActivated;
}
public Plan next() {
this.cancelPlan();
SemiConcretePlan nextPlan = (SemiConcretePlan) m_plansManager.nextPlan(this);
nextPlan.activatePlan();
return nextPlan;
}
public boolean equals(Object other) {
if (this == other)
return true;
if (other == null || !(other instanceof SemiConcretePlan) || this.hashCode() != other.hashCode())
return false;
SemiConcretePlan otherPlan = ((SemiConcretePlan) other);
if (m_id != ((SemiConcretePlan) otherPlan).m_id)
return false;
return true;
}
public abstract int hashCode();
public abstract String planDescription();
}
class AscedingPlansManager implements PlansManager{
private List<Plan> m_plansList;
private Map<Plan, Plan> m_planToHigherPlanMapping;
public AscedingPlansManager() {
m_plansList = new LinkedList();
m_planToHigherPlanMapping = new HashMap();
Plan[] plans = {
new PlanA(this),
new PlanB(this),
new PlanC(this),
new PlanD(this)
};
for(int i = 0; i < plans.length - 1; ++i) {
m_plansList.add(plans[i]);
m_planToHigherPlanMapping.put(plans[i], plans[i+1]);
}
m_plansList.add(plans[plans.length - 1]);
m_planToHigherPlanMapping.put(plans[plans.length - 1], plans[plans.length - 1]);
}
public Plan nextPlan(Plan current) {
return m_planToHigherPlanMapping.getOrDefault(current, null);
}
private void activatePlan(Plan plan) {
try {
Method privateActivateMethod = SemiConcretePlan.class.getDeclaredMethod("activatePlan");
privateActivateMethod.setAccessible(true);
privateActivateMethod.invoke(plan);
} catch(Exception e) {
e.printStackTrace();
}
}
public void cancelAll() {
for(Plan plan: m_plansList)
try {
Method privateActivateMethod = SemiConcretePlan.class.getDeclaredMethod("cancelPlan");
privateActivateMethod.setAccessible(true);
privateActivateMethod.invoke(plan);
} catch(Exception e) {
e.printStackTrace();
}
}
public Plan firstPlan() {
Plan first = m_plansList.get(0);
this.activatePlan(first);
return first;
}
public boolean[] plansToActivationState() {
boolean[] ret = new boolean[m_plansList.size()];
int index = 0;
for(Plan plan: m_plansList)
ret[index++] = plan.isActivated();
return ret;
}
}
class PlanA extends SemiConcretePlan {
public PlanA(PlansManager plansManager) {
super(plansManager);
}
public int hashCode() {
return 1;
}
public String planDescription() {
return "This is PlanA";
}
}
class PlanB extends SemiConcretePlan {
public PlanB(PlansManager plansManager) {
super(plansManager);
}
public int hashCode() {
return 2;
}
public String planDescription() {
return "This is PlanB";
}
}
class PlanC extends SemiConcretePlan {
public PlanC(PlansManager plansManager) {
super(plansManager);
}
public int hashCode() {
return 3;
}
public String planDescription() {
return "This is PlanC";
}
}
class PlanD extends SemiConcretePlan {
public PlanD(PlansManager plansManager) {
super(plansManager);
}
public int hashCode() {
return 4;
}
public String planDescription() {
return "This is PlanD";
}
}
public class Main{
public static void main(String []args){
AscedingPlansManager ascedingPlansManager = new AscedingPlansManager();
Plan currentPlan = ascedingPlansManager.firstPlan();
int i = 0, maxIterations = 5;
while((++i) <= maxIterations) {
System.out.println(currentPlan.planDescription());
System.out.println(Arrays.toString(ascedingPlansManager.plansToActivationState()));
currentPlan = currentPlan.next();
}
ascedingPlansManager.cancelAll();
System.out.println("After canceling all plans");
System.out.println(Arrays.toString(ascedingPlansManager.plansToActivationState()));
}
}
I still not sure of my implementation, I usually access private method in c++ with friend modifier, if you want to discuss anything feel free to do so.
Good Day,
I am writing a custom event handler in Java. I have a class called BoogieCarMain.java that instantiates three instances of a type called BoogieCar. Whenever any of the three instances exceeds a certain speed limit, then an event should be fired off. The code I currently have is working, so here is what I have:
// BoogieCar.java
import java.util.ArrayList;
public class BoogieCar {
private boolean isSpeeding = false;
private int maxSpeed;
private int currentSpeed;
private String color;
BoogieSpeedListener defaultListener;
public BoogieCar(int max, int cur, String color) {
this.maxSpeed = max;
this.currentSpeed = cur;
this.color = color;
}
public synchronized void addSpeedListener(BoogieSpeedListener listener) {
defaultListener = listener;
}
public void speedUp(int increment) {
currentSpeed += increment;
if (currentSpeed > maxSpeed) {
processSpeedEvent(new BoogieSpeedEvent(maxSpeed, currentSpeed, color));
isSpeeding = true;
} else {
isSpeeding = false;
}
}
public boolean getSpeedingStatus() {
return isSpeeding;
}
private void processSpeedEvent(BoogieSpeedEvent speedEvent) {
defaultListener.speedExceeded(speedEvent);
}
}
// BoogieCarMain.java
import java.util.ArrayList;
public class BoogieCarMain {
public static void main(String[] args) {
BoogieCar myCar = new BoogieCar(60, 50, "green");
BoogieCar myCar2 = new BoogieCar(75, 60, "blue");
BoogieCar myCar3 = new BoogieCar(65, 25, "pink");
BoogieSpeedListener listener = new MySpeedListener();
myCar.addSpeedListener(listener);
myCar2.addSpeedListener(listener);
myCar3.addSpeedListener(listener);
myCar.speedUp(50); // fires SpeedEvent
System.out.println(myCar.getSpeedingStatus());
myCar2.speedUp(20);
System.out.println(myCar2.getSpeedingStatus());
myCar3.speedUp(39);
System.out.println(myCar3.getSpeedingStatus());
}
}
// BoogieSpeedListener.java
public interface BoogieSpeedListener { // extends java.util.EventListener
public void speedExceeded(BoogieSpeedEvent e);
}
// MySpeedListener.java
public class MySpeedListener implements BoogieSpeedListener {
#Override
public void speedExceeded(BoogieSpeedEvent e) {
if (e.getCurrentSpeed() > e.getMaxSpeed()) {
System.out.println("Alert! The " + e.getColor() + " car exceeded the max speed: " + e.getMaxSpeed() + " MPH.");
}
}
}
// BoogieSpeedEvent.java
public class BoogieSpeedEvent { // extends java.util.EventObject
private int maxSpeed;
private int currentSpeed;
private String color;
public BoogieSpeedEvent(int maxSpeed, int currentSpeed, String color) {
// public SpeedEvent(Object source, int maxSpeed, int minSpeed, int currentSpeed) {
// super(source);
this.maxSpeed = maxSpeed;
this.currentSpeed = currentSpeed;
this.color = color;
}
public int getMaxSpeed() {
return maxSpeed;
}
public int getCurrentSpeed() {
return currentSpeed;
}
public String getColor() {
return color;
}
}
My question is: While this code works, I would like the BoogieCar type to notify BoogieCarMain directly without me have to "poll" the BoogieCar type by having to invoke the getSpeedingStatus() method.
In other words, perhaps defining a variable in BoogieCarMain.java that changes whenever one of the three cars exceeds its predefined speed limit. Is it possible to have the BoogieCar type set the variable?
Is there a cleaner way to do this?
TIA,
coson
Callbacks are ideal for this scenario.
// BoogieCarMain provides a sink for event-related information
public void handleSpeeding(BoogieCar car) {
System.out.println(car.getSpeedingStatus());
}
// MySpeedListener knows about an object that wants event-related information.
// I've used the constructor but an addEventSink method or similar is probably better.
public MySpeedListener(BoogieCarMain eventSink) {
this.eventSink = eventSink;
}
// MySpeedListener handles events, including informing objects that want related information.
// You decide if the event is an appropriate type for the sink to know about.
// Often it isn't, and instead your listener should pull the relevant info out of the event and pass it to the sink.
public void speedExceeded(BoogieSpeedEvent e) {
if (e.getCurrentSpeed() > e.getMaxSpeed()) {
// I've taken the liberty of adding the event source as a member of the event.
eventSink.handleSpeeding(e.getCar());
}
}
So thanks to the wonderful people here i've managed to get something semi workable, still have a couple bugs but maybe you guys can help me figure it out. So far none of the solution provided were a exact match (which is why i havent up voted them) but they did help me look at things in a new way and get things moving forward. So here is the current problem.
First the code then the explination
RaceButtons[RaceCounter] = new JToggleButton();
RaceButtons[RaceCounter].setIcon(RCiconSM);
RaceButtons[RaceCounter].setBorder(BorderFactory.createEmptyBorder());
RaceButtons[RaceCounter].setContentAreaFilled(false);
RaceButtons[RaceCounter].setActionCommand(temp_race.getRaceNameString(RaceCounter));
RaceButtons[RaceCounter].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
Race race = new Race(1, 1, GenderList[PHYSICAL_SEX]);
race.setRaceID(race.getRaceIDFromString(ae.getActionCommand()));
//System.out.println(race.getraceID());
if (RaceButtons[race.getraceID()].isSelected()){
RaceButtons[race.getraceID()].setBorderPainted(true);
RaceButtons[race.getraceID()].setBorder(new LineBorder(Color.blue,2));
MyRaceArray.add(new Race(race.getraceID(), 1, GenderList[PHYSICAL_SEX]));
}else{
RaceButtons[race.getraceID()].setBorderPainted(false);
};
So first i create an array of Toggle buttons and when you click it it draw the border and then getting it's info i can add it to the array for races but this lives me with another problem i cant quite figure the logic off. Namly if there are already selected button it adds another instances to the button, it shouldn't do that it should ignore iexaisting entries but that means i have to check the arry for a matching object of type Race withthe same info right? What's the best way to do that?
And when you deselect it how do i remove that same object.
This is how your code should look like with a Race class:
import java.util.ArrayList;
import java.util.List;
public class Race {
private int raceID;
private double purity;
private int strMod;
private int dexMod;
private int conMod;
private int wisMod;
public int getRaceID() {
return raceID;
}
public void setRaceID(int raceID) {
this.raceID = raceID;
}
public double getPurity() {
return purity;
}
public void setPurity(double d) {
this.purity = d;
}
public int getStrMod() {
return strMod;
}
public void setStrMod(int strMod) {
this.strMod = strMod;
}
public int getDexMod() {
return dexMod;
}
public void setDexMod(int dexMod) {
this.dexMod = dexMod;
}
public int getConMod() {
return conMod;
}
public void setConMod(int conMod) {
this.conMod = conMod;
}
public int getWisMod() {
return wisMod;
}
public void setWisMod(int wisMod) {
this.wisMod = wisMod;
}
#Override
public String toString() {
return "Race [raceID=" + raceID + ", purity=" + purity + ", strMod="
+ strMod + ", dexMod=" + dexMod + ", conMod=" + conMod
+ ", wisMod=" + wisMod + "]";
}
public static void main(String args[]) {
//create a list of race objects
List<Race> raceCollection = new ArrayList<Race>();
//create a race object
Race race = new Race();
race.setRaceID(1);
race.setPurity(0.75);
race.setStrMod(5);
race.setDexMod(7);
race.setConMod(-2);
race.setWisMod(3);
//add race object to collection
raceCollection.add(race);
//You can create and add multiple objects of race to the collection
//Iterate your list and print the objects
for(Race raceObj:raceCollection) {
System.out.println(raceObj);
}
}
}
You will be able to make it work using an ArrayList of arrays, but that possibly isn't the best way in the long run. It can be very fiddly and error-prone to deal with - what happens when you insert a new race or attribute, but forget to to change the index somewhere?
Arrays and ArrayLists are usually best reserved for situations where you actually have a sequence / list (often with a meaningful sequence order).
In your case I'd be more inclined to adopt a prototype model. Typically in Java you would represent each race with a HashMap (or a data structure containing a HashMap), there the map represents the relationship between the "Attribute ID" and the "Default Value".
Creating a new elf is then just a case of initialising the elf's attributes using the default values from his race (or a average of different races, if you want...)
Some people may suggest making an OOP class with lots of named fields. This can also work, but IMHO a prototype model is better - it gives you much more flexibility in the long run. You often want to process large groups of attributes in the some way, and doing this is pretty messy if you have to refer to each of the attribute fields individually.
import java.util.ArrayList;
import java.util.List;
public class Race
{
private final int raceID;
private final double purity;
private final int strMod;
private final int dexMod;
private final int conMod;
private final int wisMod;
public Race (int raceID, double purity, int strMod, int dexMod, int conMod, int wisMod)
{
this.raceID = raceID;
this.purity = purity;
this.strMod = strMod;
this.dexMod = dexMod;
this.conMod = conMod;
this.wisMod = wisMod;
}
public int getRaceID ()
{
return raceID;
}
public double getPurity ()
{
return purity;
}
public int getStrMod ()
{
return strMod;
}
public int getDexMod ()
{
return dexMod;
}
public int getConMod ()
{
return conMod;
}
public int getWisMod ()
{
return wisMod;
}
#Override public String toString ()
{
return "RaceID:" + raceID
+ " purity:" + purity
+ " strMod:" + strMod
+ " dexMod:" + dexMod
+ " conMod:" + conMod
+ " wisMod:" + wisMod;
}
#override public int hashCode ()
{
return raceID;
}
#override public boolean equals (Race r)
{
return (r != null && this.raceID == r.getRaceID());
}
#override public Object clone ()
{
return new Race(this.raceID,this.purity,this.strMod,this.dexMod,this.conMod,this.wisMod);
}
public static void main(String args[])
{
// simple test
ArrayList<Race> races = new ArrayList<Race>();
Race a = new Race(0,0.5,1,2,3,4);
Race b = new Race(1,0.75,2,3,4,5);
Race c = new Race(2,0.25,-1,-2,-3,-4);
races.add(a);
races.add(b);
races.add(c);
for(Race race : races)
{
// System.out.println(race.toString());
System.out.println(race);
}
}
}
Then we have the visual model, which can be handled like this:
class RacePanel implements ActionListener
{
private Map<Integer,JToggleButton> r;
private Map<Integer,Race> f;
public RacePanel()
{
r = new TreeMap<Integer,JToggleButton>();
f = new TreeMap<Integer,Race>();
}
public JToggleButton add (Race a)
{
JToggleButton button = new JToggleButton();
button.setIcon(RCiconSM);
button.setBorder(BorderFactory.createEmptyBorder());
button.setContentAreaFilled(false);
button.setActionCommand(a.getRaceID());
button.addActionListener(this);
r.put(a.getRaceID, button);
f.put(a.getRaceID, a);
}
public void remove (int raceID)
{
r.remove(a.getRaceID);
f.remove(a.getRaceID);
}
// When a button is clicked
public void actionPerformed(ActionEvent e)
{
// related race
Race a = f.get(e.getActionCommand());
// clicked button
JToggleButton b = r.get(e.getActionCommand());
// ..
}
public ArrayList<JToggleButton> getButtonList ()
{
return new ArrayList<Value>(r.values());
}
public ArrayList<Race> getRaceList ()
{
return new ArrayList<Value>(f.values());
}
public Race getRace (int raceID)
{
return f.get(raceID);
}
public JToggleButton getButton (int raceID)
{
return r.get(raceID);
}
// ..
}
I am trying to test my player class properly, I have almost done it but I am having issues with my p1.setPlayerHand method. This is the following code I have used for my player class:
Player Class:
package model;
public class Player
{
private String PlayerName;
private Hand PlayerHand;
private boolean Dealer;
public Player(String name)
{
PlayerName = name;
PlayerHand = new Hand();
Dealer = false;
}
public void setName (String name)
{
this.PlayerName = name;
}
public String getName()
{
return PlayerName;
}
public void setDealer (Boolean dealer)
{
this.Dealer = dealer;
}
public boolean getDealer()
{
return Dealer;
}
public void setPlayerHand (Hand hand)
{
this.PlayerHand = hand;
}
public void getHand()
{
PlayerHand.displayCardsinHand();
}
public static void main (String [] args)
{
Player p1 = new Player("player1");
Hand h = new Hand();
//System.out.println(p1);
p1.setName("BARRY");
System.out.println(p1.getName());
p1.setDealer(false);
System.out.println(p1.getDealer());
//this is the error that is preventing my program to run
p1.setPlayerHand(h.addCard(new Card(Suit.CLUBS, CardRank.ACE)));
p1.getHand();
}
}
The following error I receive (after testing the Player Class) is this:
Exception in thread "main" java.lang.Error: Unresolved compilation problem: The method setPlayerHand(Hand) in the type Player is not applicable for the arguments (void)
at model.Player.main(Player.java:57)
This is the Hand Class underneath (that is linked to the Player Class):
Hand Class:
package model;
import java.util.Vector;
import java.util.Random;
public class Hand
{
private Vector<Card> hand;
public Hand()
{
hand = new Vector<Card>();
}
public void addCard(Card c)
{
hand.add(c);
}
public void displayCardsinHand()
{
for (int card = 0; card < hand.size(); card++)
{
System.out.println(hand.elementAt(card));
}
}
public int getCardsinHand()
{
return hand.size();
}
public Card getCard(int position)
{
if(position >= 0 && position < hand.size())
return (Card)hand.elementAt(position);
else
return null;
}
public int getScore()
{
int value = 0;
boolean ace = false;
for (int i = 0; i < hand.size(); i++)
{
Card c;
c = getCard(i);
value = value + c.getRankValue();
if(c.getRankValue() == 1)
{
ace = true;
}
}
if(ace == true && value + 10 <= 21)
{
value = value + 10;
}
return value;
}
public static void main (String [] args)
{
Hand h = new Hand();
System.out.println(h);
h.displayCardsinHand();
System.out.println(h.getCardsinHand());
h.addCard(new Card(Suit.HEARTS, CardRank.ACE));
System.out.println(h.getCardsinHand());
h.addCard(new Card(Suit.SPADES, CardRank.JACK));
System.out.println(h.getCardsinHand());
h.addCard(new Card(Suit.DIAMONDS, CardRank.QUEEN));
System.out.println(h.getCardsinHand());
h.addCard(new Card(Suit.CLUBS, CardRank.KING));
System.out.println(h.getCardsinHand());
System.out.println(h.getCardsinHand());
h.displayCardsinHand();
h.getCard(1);
System.out.println(h.getScore());
}
}
I have tried modifying the p1.setPlayerHand testing numerous times. I appreciate any advice and tips on how to solve this issue, thank you.
If my code is too long for this post then I will gladly accept any advice on what I should do to cut it short (for future reference).
If anyone here required to see any other classes that I wrote (that may help them help me solve this error) then please notify me on here, thank you.
The method addCard doesn't return anything (void). So you can't pass the result of this method to setPlayerHand(Hand). That's what you're doing.
The code should compile and run if you change
p1.setPlayerHand(h.addCard(new Card(Suit.CLUBS, CardRank.ACE)));
to
h.addCard(new Card(Suit.CLUBS, CardRank.ACE));
p1.setPlayerHand(h);
This is because the setPlayerHand method needs to be passed an object of type Hand, but the addCard method doesn't return anything (it's declared as void).
Can someone tell me what the purpose of having inner classes? I can think of a few but may be they are not good reasons for using inner classes. My reasoning is that inner class is helpful when you want to use a class that no other classes can use. What else?
When I was learning Java we used inner classes for GUI event handling classes. It is sort of a "one time use" class that need not be available to other classes, and only is relevant to the class in which it resides.
Inner classes can be used to simulate closures: http://en.wikipedia.org/wiki/Closure_(computer_science)#Java
I use inner classes to define a structure that is best represented by the containing class, but doesn't necessarily make sense to use a separate external class to represent the structure.
To give an example I have a class that represents a particular type of network device, and the class has certain types of tests that can be run on that device. For each test there is also a potential set of errors that can be found. Each type of device may have a different structure for the errors.
With this you could do things like
List<Error> errors = RemoteDeviceA.getErrors();
With methods being available from the inner class, like
for ( Error error : errors ) {
System.out.println("MOnitor Type: " + error.getMonType());
...
}
Of course there are other ways to do this, this is just an inner class approach.
Simplified (aka incomplete) code for above:
public class RemoteDeviceA {
private String host;
private String user;
private String password;
private static List<Error> errors;
public RemoteDeviceA(String user, String host, String password) {
this.host = host;
this.user = user;
this.password = password;
login();
}
private void login() {
// Logs in
}
public void runTestA() {
List<Error> errorList = new ArrayList<Error>();
//loop through test results
if (!value.equals("0")) {
Error error = new Error(node, rackNum, shelfNum, slotNum, monType, value);
if (error.isError()) {
errorList.add(error);
}
}
setErrors(errorList);
}
private static void setErrors(List<Error> errors) {
RemoteDeviceA.errors = errors;
}
public List<Error> getErrors() {
return errors;
}
public class Error {
private String monType;
private String node;
private String rack;
private String shelf;
private String slot;
private String value;
private boolean error = false;
private boolean historyError = false;
private boolean critical = false;
private boolean criticalHistory = false;
Error(String node, String rack, String shelf, String slot,
String monType, String value) {
parseAlarm(node, rack, shelf, slot, monType, value);
}
private void parseAlarm(String node, String rack, String shelf,
String slot, String monType, String value) {
String modType = "";
if (monType.startsWith("ES_15") && !value.equals("0")) {
setMonType("ES_15");
setError(true);
} else if (monType.startsWith("SES_15") && !value.equals("0")) {
setMonType("SES_15");
setError(true);
} else if (monType.startsWith("BBE_15") && !value.equals("0")) {
setMonType("BBE_15");
setError(true);
} else if (monType.startsWith("UT_15") && !value.equals("0")) {
setMonType("UT_15");
setError(true);
setCritial(critical);
} else if (monType.startsWith("ES_24") && !value.equals("0")) {
setMonType("ES_24");
setHistoryError(true);
setError(true);
} else if (monType.startsWith("SES_24") && !value.equals("0")) {
setMonType("SES_24");
setHistoryError(true);
setError(true);
} else if (monType.startsWith("BBE_24") && !value.equals("0")) {
setMonType("BBE_24");
setHistoryError(true);
setError(true);
} else if (monType.startsWith("UT_24") && !value.equals("0")) {
setMonType("UT_24");
setHistoryError(true);
setError(true);
setCriticalHistory(true);
} else if (monType.startsWith("UT_15") && !value.equals("0")) {
setMonType("UT_15");
setError(true);
setCritial(true);
} else if (monType.startsWith("LASPWR")) {
float laserPwr = Float.valueOf(value);
if (node.startsWith("LEM_EM")) {
if ((laserPwr < 8.0) || (laserPwr > 12.0)) {
setMonType("LASERPWR");
setError(true);
}
} else if (node.startsWith("LEM10")) {
if ((laserPwr < 18.0) || (laserPwr > 22.0)) {
setMonType("LASERPWR");
setError(true);
}
}
}
if (isError()) {
setNode(node);
setRack(rack);
setShelf(shelf);
setSlot(slot);
setValue(value);
setError(true);
}
}
private void setMonType(String monType) {
this.monType = monType;
}
public String getMonType() {
return monType;
}
private void setNode(String node) {
this.node = node;
}
public String getNode() {
return node;
}
public void setRack(String rack) {
this.rack = rack;
}
public String getRack() {
return rack;
}
public void setShelf(String shelf) {
this.shelf = shelf;
}
public String getShelf() {
return shelf;
}
public void setSlot(String slot) {
this.slot = slot;
}
public String getSlot() {
return slot;
}
private void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
private void setError(boolean error) {
this.error = error;
}
public boolean isError() {
return error;
}
public void setCritial(boolean critical) {
this.critical = critical;
}
public boolean isCritical() {
return critical;
}
public void setCriticalHistory(boolean criticalHistory) {
this.criticalHistory = criticalHistory;
}
public boolean isCriticalHistory() {
return criticalHistory;
}
public void setHistoryError(boolean historyError) {
this.historyError = historyError;
}
public boolean isHistoryError() {
return historyError;
}
}
}
A list implementation that internally uses a linked list to store the elements could make good use of an inner class to represent the nodes within the list. I think you've hit the nail on the head by saying that you'd use such a class where you want to use it internally to a class but don't want it exposed - a 'one off' class that is only really useful 'here'.
I use inner classes (in C++) in situations where multiple classes, unrelated through inheritance, have conceptually similar implementation details, which form an implicit part of the public interface and ought to be named similarly.
class lib::Identifier { ... };
class lib::Person {
public:
class Identifier : public lib::Identifier { ... };
};
class lib::File {
public:
class Identifier : public lib::Identifier { ... };
};
This makes it convenient to refer to Identifier, Person::Identifier, and File::Identifier as simply Identifier, in the appropriate scopes.