Better way to structure a java class with many variables - java

I have a java class called Player. The mechanics on how the player file interacts with the server would take a lot to explain and I have no issues with the file, I just want to improve it and better my programming skills. So my question is, how would I take the many variables I have, ints, strings, booleans and make the code faster and more efficient/cleaner. Here is an example so you can see what the file looks like
enter code here
public boolean usingGlory = false;
public int[] woodcut = new int [3];
public int wcTimer = 0;
public int[] mining = new int [3];
public int miningTimer = 0;
public boolean fishing = false;
public int fishtimer = 0;
public int fishXP;
public int fishies = 0;
public int fishreqt = 0;
public int fishitem = 0;
public int fishemote = 0;
public int fishies2 = 0;
public int fishreq2 = 0;
public boolean isfishing = false;
public boolean attemptingfish = false;
public int smeltType; //1 = bronze, 2 = iron, 3 = steel, 4 = gold, 5 = mith, 6 = addy, 7 = rune
public int smeltAmount;
public int smeltTimer = 0;
public boolean smeltInterface;
public boolean patchCleared;
public int[] farm = new int[2];
public boolean antiFirePot = false;
public boolean Lattack = false;
public boolean Lranged = false;
public boolean Lmagic = false;
public boolean Ldefense = false;
public boolean Lstrength = false;
public boolean Lspecial = false;
public boolean inPits = false;
public int pitsStatus = 0;
public boolean inFunPk = false;
public boolean InDung = false;

You can break down the data into several classes, each of which contains information on a specific area.
For example, here, you have a group of variables that are related to fishing - these can be grouped into e.g. a FishingComponent class. There's also a group of information on smelting that could be split into a SmeltingComponent class, and so forth. This may lead to making the code more readable by taking groups of closely related information and functionality into their own classes.
For reusability's sake, you may wish to use an entity component system. These are popular in games programming as they allow the makeup of objects to be customised more than just inheritance. If there is, for example, an NPC that may hold information on fishing but does not have stats, the fishing component may be added to the NPC entity, and all of the code relating to fishing may be re-used.
You also mention making the code faster - unless you have a specific performance problem, you are probably attempting to prematurely optimise. However, you may wish to look into pooling objects if they need to be garbage collected a lot, as in games written in garbage collected languages, garbage collection cycles can be one of the biggest cause of framedrops.

You might want to apply two common OOP techniques: encapsulation and composition. First of all, it's bad practice to have a bunch of public fields in your class. Instead, encapsulate them using getter and setter methods. Here's an example for the first two variables:
private boolean usingGlory = false;
public boolean isUsingGlory() {
return usingGlory;
}
public void setUsingGlory(boolean using) {
usingGlory = using;
}
private int[] woodcut = new int[3];
public int[] getWoodcut() {
return woodcut;
}
public void setWoodcut(int[] woodcut) {
this.woodcut = woodcut;
}
For more info, see Wikipedia.
The second technique is composition. You're right not to like having so many variables in your class. Instead of having all the variables be part of the Player class, group them into classes containing related items. You can even group methods, when appropriate! Here's an example that uses your fishing variables:
public class Player {
//...
private FishingState fishingState = new FishingState();
//Getter and setter
//...
}
public class FishingState {
private boolean fishing = false;
private int timer = 0;
private int XP;
private int fishies = 0;
private int reqt = 0;
private int item = 0;
private int emote = 0;
private int fishies2 = 0;
private int req2 = 0;
//Getters and setters
//A constructor and some methods:
public FishingState(int XP) {
this.XP = XP;
}
public void resetTimer() {
timer = 0;
}
}
Now, player.fishemote = 3 becomes player.getFishingState().setEmote(3). Longer, but clearer.

Related

Getting Variables From Java constructor

I'm new to Java programming, sorry if this is a dumb question.
I find it hard to word this question properly, but I have an assignment to create a aircraft class that can make aircraft land, takeoff etc. And need to test it using Testclass. When the new object are entered it automatically assigns a unique ID to the aircraft in the constructor.
I can do this using a instance method fine as it has a return value which is returned to to Testclass. The question wants me to do this in the constructor itself, however, the constructor never returns anything. So the variable never gets sent to the Testclass. I clearly am not understanding OOP properly. Even when I try to just use a getter method to get the ID created in the constructor it gives me the initialized variable before the the constructor has worked on this. This is the code I have so far and its completely wrong I know but if someone could point me in the right direction or tell me how to word this question better it would be a massive help.
// I need to enter 3 aircraft into the system in the testclass
public class Aircraft {
private int aircraftID;
private static int lastID;
private String airportcode;
private int ID = 100;
private int count;
public Aircraft(int a, int b, int c){
// Constructor
// Assign ID
this.ID = a;
lastID = ID;
ID++;
this.ID =b;
lastID = ID;
ID++;
}
}
OK, you want to create an Aircraft that has an automatically-assigned unique identifier, and can take off and land. That implies you need a field for tracking the identifier, a field for tracking whether it's in the air (or not), and methods for the take off and land operations. You also need a static field for generating the unique identifiers. (Note that this implementation isn't thread safe.)
private class Aircraft {
private static int staticId = 0;
private int uniqueId = 0;
private boolean onGround = true; // Aircraft start on the ground in this implementation
public Aircraft(){
this.uniqueId = staticId; // putting this line first makes uniqueId zero-indexed in effect
staticId++;
}
public void land(){
onGround = true;
}
public void takeoff(){
onGround = false;
}
public boolean isFlying(){
return !onGround; // If it's not on the ground, it's flying
}
public int getUniqueId(){
return uniqueId;
}
}
Unit tests checks all of the methods and expected functionality of the class in question:
import org.junit.Test;
import static org.junit.Assert.*;
import Aircraft;
class Testclass {
private final Aircraft aircraft = new Aircraft();
#Test
public void hasId(){
aircraft.getUniqueId() >= 0;
}
#Test
public void canLand(){
assertTrue(aircraft.land());
}
#Test
public void canTakeOff(){
assertTrue(aircraft.takeOff());
}
#Test
public void checkFlightOperationsAreTrackedCorrectly(){
aircraft.land();
assertFalse(aircraft.isFlying());
aircraft.takeOff();
assertTrue(aircraft.isFlying());
}
}
As pointed out a constructor does not return anything (the simplified version is that with new it returns an object instance). I am kinda guessing at what you are trying to acomplish, but I'll have a go anyways. It seems to me that you are trying to cram the construction of 3 objects into one constructor - which is why your constructor has 3 parameters. Also you are playing havoc with the IDs.
I have removed all the variables that I didnt quite understand, leaving only ID that increments with each instantiated Aircraft. The #Override is mainly just for show.
public class Aircraft {
private int aircraftID;
private static int lastID = 0;
#Override
public String toString(){
return "Aircraft_" + this.aircraftID;
}
public Aircraft() {
lastID++;
this.aircraftID = lastID;
}
}
I took the liberty and wrote the TestClass just to see if we have the same thing in mind. Again the printAircraft() method is for show.
public class TestClass {
private List<Aircraft> aircrafts;
public TestClass(){
aircrafts = new ArrayList<>();
}
public void addAircraft(Aircraft a){
aircrafts.add(a);
}
public void printAircraft(){
Iterator<Aircraft> it = aircrafts.iterator();
while(it.hasNext()){
System.out.println(it.next().toString());
}
}
}
and to test it, we create and instance of TestClass add 3 Aircraft instances and print out the contents
public static void main(String[] args) {
TestClass tc = new TestClass();
tc.addAircraft(new Aircraft());
tc.addAircraft(new Aircraft());
tc.addAircraft(new Aircraft());
tc.printAircraft();
}
This would be the case if you are to write the TestClass. If that is given, it would help to know what it looks like - maybe that would help us understand better.

Class instance assistance

I am working on a program that is supposed to implement an electronic store. I had to create 3 classes (desktop, laptop and fridge) with specific defined functionality which I did. I am stuck on how to create the Electronic store class in which the constructor for this class
must create three instances of each of the previous three classes (9 items in total, using the
constructors defined in those classes) and store them within the ElectronicStore instance being created. I am unsure on how to do the above and would appreciate assistance. Below is what I have gotten so far.
// Desktop class
public class Desktop{
double speed = 0;
int ram, storage = 0;
boolean storageType;
public Desktop(double s, int r, int p, boolean t){
speed = s;
ram = r;
storage = p;
storageType = false;
}
// This is a String representation of the Desktop object
//#Override
public String toString(){
return "#"+speed+"#"+ram+"#"+storage;
}
}
// Laptop class
public class Laptop{
double CPU;
int RAM, storage, size;
boolean storeType;
public Laptop(double C, int R, int st, int si){
CPU = C;
RAM = R;
storage = st;
size = si;
storeType = false;
}
// This is a String representation of the Desktop object
public String toString(){
return "#"+CPU+"#"+RAM+"#"+storage+"#"+size;
}
}
// Fridge class
public class Fridge{
double fridge;
boolean freezer;
String color;
public String toString(){
return "#"+fridge+"#"+color;
}
}
// ElectronicStore class (which i am stuck with)
public class ElectronicStore{
public ElectronicStore()
{}
}
You create an instance of a class like so:
Desktop desktopOne = new Desktop(x, y, z);
To store them you can either have class variables (like you have for speed, ram) etc., or you could use a data structure like a list. Further clarification needed on that point.
I think it should be something like this
public class ElectronicStore{
private ArrayList<Fridge> fridges = new ArrayList<>();
public ElectronicStore()
{
Fridge fridge1 = new Fridge();
Fridge fridge2 = new Fridge();
Fridge frigde3 = new Fridge();
fridges.add(fridge1);
fridges.add(fridge2);
fridges.add(fridge3);
...
}
}
And you have to do the same thing to create the other objects.

Java - changing a variable through pass-by-value

So I've read about the pass-by-value nature of Java and I've tried to change my variable after passing it to a function by having the function return the variable again. I didn't succeed in that.
My code
public class Logic {
private int position;
public class Logic(){
position = 1;
}
public void appendPosition(){
position = calculatePosition(position);
}
}
This is the barebones code. I call this method from an instance of Logic which is instantiated in another class:
public class MainLogic {
ILogic L;
public MainLogic(ILogic L){
this.L = L;
}
public void start(){
L.appendPosition();
}
}
Through repeated debugging I find to my dismay that the position variable does not change at all. The position variable passed to calculatePosition changes fine, as expected. What am I missing? I've tried making the variable public and static.
calculatePosition
private int calculatePosition(int position){
position += 6;
if(snakeLocations[position]>0) {
position -= 6;
}
else if(ladderLocations[position]>0) {
position += 6;
}
return position;
}
private final int[] snakeLocations = new int[] {0,0,0,0,0,0,0,0,0,9,0,0,0,13,0,0,0,0,0,19,0,0,0,0,0};
private final int[] ladderLocations = new int[] {0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,15,0,0,0,0,20,0,0,0,0};
public class Logic {
private int position;
public Logic(){
position = 1;
}
//to get position.....................
public int getPosition(){
return this.position;
}
public void appendPosition(){
position = calculatePosition(position);
}
private int calculatePosition(int position){
position += 6;
if(snakeLocations[position]>0) {
position -= 6;
}
else if(ladderLocations[position]>0) {
position += 6;
}
return position;
}
private final int[] snakeLocations =
new int[] {0,0,0,0,0,0,0,0,0,9,0,0,0,13,0,0,0,0,0,19,0,0,0,0,0};
private final int[] ladderLocations =
new int[] {0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,15,0,0,0,0,20,0,0,0,0};
}
//next class
public class MainLogic {
Logic L;
public MainLogic(Logic L){
this.L = L;
}
public void start(){
L.appendPosition();
}
public static void main(String[] args) {
Logic L = new Logic();
MainLogic ml = new MainLogic(L);
System.out.println(ml.L.getPosition());
ml.start();
System.out.println(ml.L.getPosition());
}
}
Let's read your code.
// There is a logic class.
public class Logic {
// So Logic has a position. it starts with zero.
private int position;
// Logic also has an inner class, also called Logic.
public class Logic(){
position = 1;
// When a new Logic().Logic() is created, the instance
// variable of the parent instance gets set to one. WHAT?!?
}
// ... lots of code
}
So, It's a bit like that Yo Dawg! meme - I heard you like Logic, so we've put A logic instance into your Logic instance so you can Logic while your Logic.
You probably want a constructor.
// So this is Logic.
public class Logic {
private int position;
// When an Logic instance is created, position starts with 1.
public Logic(){
this.position = 1;
}
Ok. So we're not talking about Yo Dawg Memes.
So Let's talk pass by value.
Pass-by-value means classes are like very egotistic children: You can't play with their toys, unless they tell you so.
This is a good thingĀ® since this means only the owning instance is allowed to change their private state. Trust me, it prevents quite a bit of havoc.
One way to allow the outside world to actually change the state is by using query and mutator methods. Back in the day, we used to call them getter and setter, but that sounds too simple, so software architects will usually use the fancier term.
But... all of this doesn't really apply since calculatePosition() is defined at Logic. Oops.
Let's try this:
Renaming some instance variables
Be a bit verbose to help the debugger. baby steps.
(Also, dropping a few jokes to fish for upvotes).
public class Logic {
private int position = 1;
public void appendPosition(){
// When debugging strange stuff,
// keep each step simple.
// Is calculatePosition working as it should?
int newPosition = calculatePosition(this.position);
this.position = newPosition;
}
// Always use parameters as final. It's good karma.
// You don't NEED to declare them as final,
// but let's try to be EXTRA clear.
private int calculatePosition(final int targetPosition){
// Yes, make as much as you can immutable
// You'll save a ton of mental bandwidth.
final int localCopy = targetPosition +6;
if(snakeLocations[localCopy]>0) {
return (localCopy -6);
// Don't force the maintenance programmer to
// read all your stuff. Return often, return early.
// This isn't Cc++, where you need to
// actually free your reference/pointers,
// so there's no point enforcing a single return.
}
if(ladderLocations[localCopy]>0) {
return (localCopy+6);
}
return localCopy;
}
}
So... Did this worked as it should?
I found the answer. This is often my mistake in posting here. I try to strip down my code as much as possible to ease the work for you guys, but sometimes the problem lies outside of the scope of what I provide due to a lack of understanding, or oversight, on my part.
I was actually calling MainLogic from two levels above:
public mainFrame() {
initComponents();
logic = Factory.getMainLogic();
}
where
public static class Factory {
public MainLogic getMainLogic(){
PlayerLogic pL = new PlayerLogic();
ImageLogic iL = new ImageLogic();
DieLogic dL = new DieLogic();
MainLogic mainLogic = new MainLogic(pL,iL,dL);
return mainLogic;
}
}
I forgot I had accidentally put Factory as static. My sincerest apologies for wasting your time.

Design Pattern: Extending a List of Constants

I know the title isn't very descriptive but hopefully I can clarify some things with code. I have a class that looks like this:
public abstract class Entity {
protected final static int BASE_STATE_SIZE = 3;
protected final static int AGE = 0;
protected final static int X = 1;
protected final static int Y = 2;
protected double[] state;
public Entity () {
state = new double[getStateSize ()];
...
}
protected void initDefaultState () {
state[AGE] = 0;
state[X] = Math.random () * Renderer.size.width;
state[Y] = Math.random () * Renderer.size.height;
}
protected abstract int getStateSize ();
}
public class Critter extends Entity {
protected final static int STATE_SIZE = Entity.BASE_STATE_SIZE + 1;
protected final static int HUNGER = Entity.BASE_STATE_SIZE + 0;
public Critter () {
...
}
protected void initDefaultState () {
super.initDefaultState ();
state[HUNGER] = 0;
}
protected int getStateSize () {
return STATE_SIZE;
}
}
To give a bit more context: entities are just generic objects. Critter is one example of a more specific object. The state of an entity changes frequently throughout its lifetime. In this case, a critter's position, x, y, and hunger change multiple times per second. State values are assigned in the subclass (and occasionally in the main Entity class like age which is updated uniformly for all subclasses). No other outside object should be able to change the state of an entity, only the entity object itself.
This whole design seems a bit fishy to me but I'm not sure how to change it. One alternative would be to make the "state" its own class that is extended by those classes that extend entity. However, with this method each state parameter would require its own function and the parameters could not be iterated through like they can be now. I was wondering if there was a defined design pattern for what I'm doing or if I should just stick with what I have. Thanks!

Better way to map from String constants to int constants in Java

I have a load of images of musical symbols which I need to do some processing on and for each one I need to get the integer code corresponding to its file name. There are 23 possible file name strings and 23 integer code and there are many images with the same name under different directories.
The solution I have so far is given (abbreviated) below. I have just defined a load of int and String constants and then written a method which is just a huge chain of if statements to do the translation.
What would be a better way to achieve the same effect? The way I've done it seems really awful! I thought about using some kind of Map, but I wasn't sure of the best way to do so.
public class Symbol {
public static final int TREBLE_CLEF = 0;
public static final int BASS_CLEF = 1;
public static final int SEMIBREVE = 2;
// ...
public static final String S_TREBLE_CLEF = "treble-clef";
public static final String S_BASS_CLEF = "bass-clef";
public static final String S_SEMIBREVE = "semibreve";
// ...
public static int stringCodeToIntCode(String strCode) {
if (strCode == S_TREBLE_CLEF) {
return TREBLE_CLEF;
} else if (strCode == S_BASS_CLEF) {
return BASS_CLEF;
} else if (strCode == S_SEMIBREVE) {
return SEMIBREVE;
} //...
else {
return -1;
}
}
}
I think you are looking for Enum where you can have String constant and its value.
Example:
public enum YourEnumClass{
STRING_CONST (5),
STRING_CONST2 (7),
.....
//constructor
//getValue() method
}
read linked tutorial for more details.
enum StringToInt{
TREBLE_CLEF(0),
......
}
Enum is the way to go.
Another example:
public enum Color {
WHITE(21), BLACK(22), RED(23), YELLOW(24), BLUE(25);
private int code;
private Color(int c) {
code = c;
}
public int getCode() {
return code;
}
how about a hashmap
HashMap<String,Integer> hm=new HashMap<String,Integer();
hm.put("treble-clef",0);
//rest
and get it by using this
int value=hm.get("treble-clef");

Categories