I'm rather fresh in programming and I try to make simple app. App will allow user to make a character sheet for popular RPG game. Right now I trying to model it (on paper) and have (maybe a stupid one) question.
Each character have set of skills - a lot (33). And each skill cane have value of 0-5. Now my question is: is it better to make 33 ints insied Character object or make Class Skill and make array of Skills in Character? My knowledge of Java is not good enough to decide :( If anyone find some useful article about it or can just simply explain it to me I would be grateful.
I just hope it is not completely stupid question :)
Have a nice day!
If you have a fixed number of skills you can use multiple attributes, will increase readability when used, but will make your class a bit ugly and less mantainable.
If values are always an int, I would reccomend to use a Map instead of array or Collection.
Map<String, Integer> skills;
So you can have a class with nice declaration and refer to skills by name and not by position in the array:
Integer strenghtLevel = skills.get("strenght");
I definitely recommend to create a specific Skill class. Today you are using ints from 0 to 5; but such things tend to become more complex pretty fast.
Therefore you should carefully design the "Skill" class upfront (you might also consider to have a Skill interface; as you might face the need to have different implementations (for different skill types) at some future point).
You character class could then be using a dynamic container; for example java.util.ArrayList to hold all the various skills.
It's probably better to make a class skill, because then you can ensure each skill has a name and a value. Then, you can also do things like creating a method to print out or display the name and value, and if you want to add another attribute to the skill, it is fairly easy.
You could use an array of int elements. It should be enough, unless you want some custom logic. If the values should have states and actions, then they should be objects.
Related
Is nesting collections in Java something that I should be doing?
I'm currently working on a project where I want to have a bunch of hashmaps that would contain a String key and an arrayList value. That way when I create and add an object of another class to the collection, it would be able to use some piece of information that if it matched up with one of the keys of one of the hashmaps it would then be deposited in the associated arrayList value. That way the list can later on be accessed through the correct key for a specific hashmap.
Is this a good idea? Or is it too convoluted and if so is there a better way to do this?
There are times to nest, for sure. But in the humble opinion of this seasoned dev, you shouldn't do it unless you have a good reason. All too often you would be much better off with some class that represents the inner collection.
So if you find yourself with a Map<String,List<Foo>> ask yourself what that List<Foo really represents. If it's Map<String,List<Student>> then maybe you need Map<String, Roster> or Map<String, Team>. I find this yields faster time to market and fewer bugs. The fact you're asking the question means you think there's a chance that might be true too.
Say, for example, I want to make a cash register program. Ignoring, for the sake of being compact, that one wouldn't use floats for currency my first instinct is to use an enum for the denominations, something along the lines of :
private enum Currency {
ONE_HUNDRED(100.00f),
FIFTY( 50.00f),
TWENTY( 20.00f),
TEN( 10.00f),
FIVE( 5.00f),
TWO( 2.00f),
ONE( 1.00f),
HALF_DOLLAR( 0.50f),
QUARTER( 0.25f),
DIME( 0.10f),
NICKEL( 0.05f),
PENNY( 0.01f);
private final float value;
Currency(float value) {
this.value = value;
}
public float getValue() {
return this.value;
}
#Override
public String toString() {
return this.name().replace("_", " ");
}
}
But last I followed instinct, sans forethought, and did something similar for a Morse Code Converter, someone suggested that I use a map instead, explicitly a Bimap. I see the appeal of that collection in that particular scenario, but generally speaking I wanted to inquire if there were any reason to prefer one when the other could be used? If instead of the above code I did this:
Map<String, Float> currency = new LinkedHashMap<>();
currency.put("One Hundred", 100.00f);
currency.put("Fifty", 50.00f);
currency.put("Twenty", 20.00f);
currency.put("Ten", 10.00f);
currency.put("Five", 5.00f);
currency.put("Two", 2.00f);
currency.put("One", 1.00f);
currency.put("Half Dollar", 0.50f);
currency.put("Quarter", 0.25f);
currency.put("Dime", 0.10f);
currency.put("Nickel", 0.05f);
currency.put("Penny", 0.01f);
Would it be superior for any reason?
In cases like these were either could be utilized, are there any performance advantages to using one over another? Is one more preferable/conventional? More maintainable/adaptable?
Is there any rule of thumb I could use for when I should use one over the other?
Here are things I like to keep in mind:
Enums are best used (and in the languages I know of, may only be used) to define a known set of items ahead of time. This has a nice benefit of treating what really boils down to frequently used "data" as code in a very readable way.
In my opinion, any code that relies on frequently hardcoded strings, like you would need to use if implementing data like that in a map is more difficult to read and maintain. This leads to "magic strings", which is a no-no when avoidable.
It's not immediately clear what should exist in the map until you go check, and it's not clear if it's potentially being modified elsewhere. Consider, that if you got an enum value wrong, the code will not even compile. Get a string key wrong, and you might not notice until much later.
Regarding performance, I doubt there is a large difference between the two. Enums are treated largely the same as objects, I suppose the benefit comes from accessing the data as a field on the object rather than a hash lookup.
This article doesn't go in depth as I would like, but may be a good starting point: Memory Consumption of Java Data Types
It is quite common practice to use an enum as keys for a known map and that offers another way of associating data with a set of specific items (rather than setting them as fields on the enum). I believe this approach would be my preferred method since setting lots of fields on an enum makes them feel too much like a class rather than a method of referencing. This doesn't have the same problems as a normal map because since the keys must be enums you don't need to worry about any other keys "accidentally" being added to the map. It seems Java as a whole supports this approach as they provide the EnumMap class.
I would say that the main difference between your two pieces of code is that in case of enum you have fixed list of denominations which are "type-safe". While operating with strings and maps it is very easy to misspell some string, introducing bugs that are hard to spot.
I would use enum in this case it is more sensible and if this were something that were to be used by other people enum's have the associated values display for you if you are using pretty much any ide, where as if you are using a map neither the key or the value is readily available to you. There are other reasons but that was one that came to mind.
Would it be superior for any reason?
The Map design would be appropriate for dynamic data, whereas the enum design would be appropriate for fixed data.
In cases like these were either could be utilized, are there any
performance advantages to using one over another?
Insignificant.
Is one more preferable/conventional?
Only when considering the specific problem to be solved.
More maintainable/adaptable?
Again, it depends on the problem you're trying to solve.
Is there any rule of thumb I could use for when I should use one over
the other?
Whether you're working with a limited, non-varying dataset known at compile time.
I'm developing a game which will have the same sort of system as pokemon does, i.e. every player will have a 'type'(fire,water,grass etc.). When players fight, I need to determine what factr to multiply attacks by, to create strengths and weaknesses. So far I'm using a switch in each 'type' class which takes another 'type' class as input and returns the multiplication factor. With only three of these 'type' classes, I'm writing a lot of ode and I can foresee it getting out of hand in the future when I want to add more.
So my question is, how can I implement a DRY solution for determining strengths and weaknesses of each type? I've attached a table of the pokemon types as a reference for what it is I am trying to do.
How about enumerating the types, and building a 2D matrix that looks just like the one you posted. Whenever you need the "factor" for a battle, look the factor up using the attacker and defender as indices in the 2D array. Lookups would be fast and the code would be pretty clean.
Sample use cases would look something like this:
factor = factorTable[FIRE][WATER]; // would set factor to 0.5
factor = factorTable[WATER][FIRE]; // would set factor to 2.0
As Noctua suggested, it might be a good idea to have the actual data in a config file. That way you can easily change it without recompiling. If you go for that option, you'd need some kind of parsing function to create the matrix at the beginning of the program.
An even better step to take next would be to encapsulate the table behavior and type representation in classes. The underlying implementation could still be the same (or change, that's the point) but you wouldn't expose the table nor the enumerations directly.
factor = StrengthFactors(Player1.Type(), Player2.Type()); // or similar
I think you should use a single array of strings to store the different types. Then you use a 2D Matrix to store multipliers. The idea is to use the id of this array of string to know where is the multiplier. You will have a O(n) complexity to find the multiplier you want.
Lets say we have a bunch of data (temp,wind,pressure) that ultimately comes in as a number of float arrays.
For example:
float[] temp = //get after performing some processing (takes time)
float[] wind =
Say we want to store these values in memory for different hours of the day. Is it better to put these on a HashMap like:
HashMap maphr1 = new HashMap();
maphr1.put("temp",temp);
maphr1.put("wind",wind);
...
Or is it better to create a Java object like:
public class HourData(){
private float[] temp,wind,pressure;
//getters and setters for above!
}
...
// use it like this
HourData hr1 = new HourData();
hr1.setTemp(temp);
hr1.setWind(wind);
Out of these two approaches which is better in terms of performance, readability, good OOP practice etc
You're best off having an HourData class that stores a single set of temperature, wind, and pressure values, like this:
public class HourData {
private float temp, wind, pressure;
// Getters and setters for the above fields
}
If you need to store more than one set of values, you can use an array, or a collection of HourData objects. For example:
HourData[] hourDataArray = new HourData[10000];
This is ultimately much more flexible, performant, and intuitive to use than putting storing the arrays of data in your HourData class.
Flexibility
I say that this approach is more flexible because it leaves the choice of what kind of collection implementation to use (e.g. ArrayList, LinkedList, etc.) to users of the HourData class. Moreover, if he/she wishes to deal just with a single set of values, this approach doesn't force them to deal with an array or collection.
Performance
Suppose you have a list of HourData instances. If you used three float arrays in the way that you described, then accessing the i'th temp, wind, and pressure values may cause three separate pages to be accessed in memory. This happens because all of the temp values will be stored contiguously, followed by all of the wind values, followed by all of the pressure values. If you use a class to group these values together, then accessing the i'th temp, wind, and pressure values will be faster because they will all be stored adjacent to each other in memory.
Intuitive
If you use a HashMap, anyone who needs to access any of the fields will have to know the field names in advance. HashMap objects are better suited to key/value pairs where the keys are not known at compile time. Using an HourData class that contains clearly defined fields, one only needs to look at the class API to know that HourData contains values for temp, wind, and pressure.
Also, getter and setter methods for array fields can be confusing. What if I just want to add a single set of temp, wind, and pressure values to the list? Do I have to get each of the arrays, and add the new values to the end of them? This kind of confusion is easily avoided by using a "wrapper" collection around an HourData that deals only with single values.
For readability i would definately go for a object since it makes more sense. Especially since you store different datacollections like the wind longs have a different meaning as the temp longs.
Besides this you can also store other information like the location and time of your measurement.
Well if you dont have any key to differentiate different instances of the same object. I would create HourData objects and store them in a array list.
Putting data in a contained object always increases the readability.
You have mentioned bunch of data, So I would rather read it as collection of data.
So the answer is , if something already available in Java collection framework out of box , why do you want to write one for you.
You should look at Java collection classes and see which fits your requirement better, whether it is concurrent access, fast retrieve time or fast add time etc etc..
Hope this helps
EDIT----
Adding one more dimension to this.
The type of application you are building also affects your approach.
The above discussion rightly mentions readability, flexibility , performance as driving criteria for your design.
But the type of application you are building is also one of the influencing factors.
For example, Lets say you are building a web application.
A Object which is stored in memory for a long time would be either in Application or Session Scope. So you will have to make it immutable by design or use it for thread safe manner.
The business data which remains same across different implementations should be designed as per OOP or best practices but the infrastructure or Application logic should more be your framework driven.
I feel what you are talking, like keeping an object for a long time in memory is more a framework driven outlook, hence I suggested use Java Collection and put your business objects inside it. Important points are
Concurrent Access Control
Immutable by design
If you have a limited and already defined list of parameters then it's better to use the second approach.
In terms of performance: you don't need to search for key in hashmap
In terms of readability: data.setTemp(temp) is better than map.put("temp", temp). One of the benefits of the first approach is that typing errors will be catched during the compilation
In terms of good OOP practices: first approach has nothing to do with OOP practices. Using the second approach you can easily change the implementation, add new methods, provide several alternative data object implementations, etc.
But you might want to use collections if you don't know the parameters and if you want to work with uncategorized(extensible) set of parameters.
I know that more-dynamic-than-Java languages, like Python and Ruby, often allow you to place objects of mixed types in arrays, like so:
["hello", 120, ["world"]]
What I don't understand is why you would ever use a feature like this. If I want to store heterogenous data in Java, I'll usually create an object for it.
For example, say a User has int ID and String name. While I see that in Python/Ruby/PHP you could do something like this:
[["John Smith", 000], ["Smith John", 001], ...]
this seems a bit less safe/OO than creating a class User with attributes ID and name and then having your array:
[<User: name="John Smith", id=000>, <User: name="Smith John", id=001>, ...]
where those <User ...> things represent User objects.
Is there reason to use the former over the latter in languages that support it? Or is there some bigger reason to use heterogenous arrays?
N.B. I am not talking about arrays that include different objects that all implement the same interface or inherit from the same parent, e.g.:
class Square extends Shape
class Triangle extends Shape
[new Square(), new Triangle()]
because that is, to the programmer at least, still a homogenous array as you'll be doing the same thing with each shape (e.g., calling the draw() method), only the methods commonly defined between the two.
As katrielalex wrote: There is no reason not to support heterogeneous lists. In fact, disallowing it would require static typing, and we're back to that old debate. But let's refrain from doing so and instead answer the "why would you use that" part...
To be honest, it is not used that much -- if we make use of the exception in your last paragraph and choose a more liberal definition of "implement the same interface" than e.g. Java or C#. Nearly all of my iterable-crunching code expects all items to implement some interface. Of course it does, otheriwise it could do very little to it!
Don't get me wrong, there are absolutely valid use cases - there's rarely a good reason to write a whole class for containing some data (and even if you add some callables, functional programming sometimes comes to the rescue). A dict would be a more common choice though, and namedtuple is very neat as well. But they are less common than you seem to think, and they are used with thought and discipline, not for cowboy coding.
(Also, you "User as nested list" example is not a good one - since the inner lists are fixed-sized, you better use tuples and that makes it valid even in Haskell (type would be [(String, Integer)]))
Applying a multimethod to the array might make some sense. You switch the strategy to a more functional style in which you focus on a discrete piece of logic (i.e. the multimethod) instead of a discrete piece of data (i.e. the array objects).
In your shapes example, this prevents you from having to define and implement the Shape interface. (Yes, it's not a big deal here, but what if shape was one of several superclasses you wanted to extend? In Java, you're SOL at this point.) Instead, you implement a smart draw() multimethod that first examines the argument and then dispatches to the proper drawing functionality or error handling if the object isn't drawable.
Comparisons between functional and object-oriented styles are all over the place; here are a couple relevant questions that should provide a good start: Functional programming vs Object Oriented programming and Explaining functional programming to object-oriented programmers and less technical people.
Is there reason to use the former over
the latter in languages that support
it?
Yes, there is a very simple reason why you can do this in Python (and i assume the same reason in Ruby):
How would you check that a list is heterogenous?
It can't just compare the types directly because Python has duck typing.
If all the object have some common typeclass Python has no way to guess that either. Everything supports being represented anyways, so you should be able to put them in a list together too.
It wouldn't make any sense to turn lists into the only type that needs a type declaration either.
There is simply no way to prevent you from creating a heterogenous list!
Or is there some bigger reason to use
heterogenous arrays?
No, I can't think of any. As you already mentioned in your question, if you use a heterogenous arrays you're just making things harder than they have to be.
There is no reason not to support heterogeneous lists. It's a limitation for technical reasons, and we don't like those.
Not everything needs to be a class!
In Python, a class is basically a souped up dictionary with some extra stuff anyway. So making a class User is not necessarily any clearer than a dictionary {"name": ..., "id": ...}.
There is nothing to stop you having a heterogeneous array in Java. It is considered poor programming style and using proper POJOs will be faster/more efficient than heterogeneous arrays in Java or any other language as the types of the "fields" are statically known and primitives can be used.
In Java you can
Object[][] array = {{"John Smith", 000}, {"Smith John", 001}, ...};
Eterogenous lists are very useful. For instance, to make the game of snake, I can have a list of blocks like this:
[[x, y, 'down'], [x1, y1, 'down']]
instead of a class for the blocks, and I can access faster to every element.
In Lua an object and an array are the same thing so the reason is more clear. Let's say that Lua takes the weak typing to the extreme
Apart from that, I had a Google Map object and I needed to delete all markers created so far in that map. So I ended up creating an array for markers, an array for circles and an array for places. Then I made a function to iterate over those three arrays and call .remove() on each of them. I then realized that I could just have a single non homogeneous array and insert into them all the objects and iterate once over that array
Here is a simple answer:
N.B. I am not talking about arrays that include different objects that
all implement the same interface or inherit from the same parent, e.g.:
Everything extends java.lang.Object... and that's plenty. There is no reason not to have Object[] and put anything you like in. Object[] are exceptionally useful in any middleware like persistence layer.