I'm creating a Java class that should encapsulate the six orbital elements of a celestial object, the six osculating elements of the same celestial object, the mass of the body and the name of the body. This means that my Java object must be created with no less than fourteen parameters, and I am now thinking about including another four constants of perturbation as parameters, which will bring that number up to eighteen.
This is how it looks with fourteen parameters:
new Planet("Mercury", 3.3022E23,0.387098, 0., 0.205637, 0.00002123, 7.00559, -0.00590158, 252.252, 149473., 77.4577, 0.1594, 48.3396, -0.122142)
I've looked around people say that a class that takes in more than ten parameters is probably poorly designed. They also say that a class should do one thing and one thing only. Well, I'm just doing one thing literally, the only thing the class does so far is calculating the position of the celestial object with those parameters as a function of time.
What is best practice for dealing with this situation?
I recommend the Bloch Builder, by Joshua Bloch (item 2) in Effective Java, 2nd edition:
http://www.informit.com/articles/article.aspx?p=1216151&seqNum=2
It is a pattern designed specifically for classes with lots of fields, although it is intended for optional parameters, which is not your case. However, I still think this might be a good way for you to approach it. Such as
Planet p = new Planet.Builder("Mercury").gravity(3.3022E23).
anotherAttribute(0.387098).avgTemp(0.).
somethingElse(0.205637).andAnotherThing(0.00002123).
....
build();
(change them to meaningful stuff...I have no idea what the numbers actually represent :)
I recommend against setters in the Planet object, in order to make the fields immutable ( https://www.google.com/search?q=fields+immutable+java+benefit).
I hope this helps.
I would prefer combining the already mentioned solutions - as you write in your intro "I'm creating a Java class that should encapsulate the six orbital elements of a celestial object, the six osculating elements of the same element, the mass of the body and the name of the body.", it seems to me that you can group each six parameters into a new datastructure, so that you end up with four parameters for the Planet constructor (name, mass and the two parameter objects with six own values each) - next step I would ask myself if the six orbital and osculating elements somehow carry extra meaning or are merely a group of six (as in "arbitrary number") elements and can therefore be represented as a list.
I would just have a bunch of setters. Maybe use name as constructor parameter. Just to make it clearer to read. Figuring out which of those 14+ parameters is which is just too difficult for the reader if you set them all in the constructor. Or use a builder as suggested by others.. Both are about the same for me.
I would recommend you to use Builder Design Pattern.
If you are using lombok annotation all the verbose code can be generated by using #Builder annotation.
#Builder
class Some{
private String a;
private String c;
private String d;
private String e;
}
You can generate object with the following semantics:
Some someObject = Some.builder()
.a("a")
.b("b)
.c("c")
.d("d")
.e("e)
.build();
Related
This question already has answers here:
Class Object vs Hashmap
(3 answers)
Closed 3 years ago.
I have some piece of code that returns a min and max values from some input that it takes. I need to know what are the benefits of using a custom class that has a minimum and maximum field over using a map that has these two values?
//this is the class that holds the min and max values
public class MaxAndMinValues {
private double minimum;
private double maximum;
//rest of the class code omitted
}
//this is the map that holds the min and max values
Map<String, Double> minAndMaxValuesMap
The most apparent answer would be Object Oriented Programming aspects like the possibility to data with functionality, and the possibility to derive that class.
But let's for the moment assume, that is not a major factor, and your example is so simplistic, that I wouldn't use a Map either. What I would use is the Pair class from Apache Commons: https://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/tuple/Pair.html
(ImmutablePair):
https://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/tuple/ImmutablePair.html
The Pair class is generic, and has two generic types, one for each field. You can basically define a Pair of something, and get type safety, IDE support, autocompletion, and the big benefit of knowing what is inside. Also a Pair features stuff that a Map can not. For example, a Pair is potentially Comparable. See also ImmutablePair, if you want to use it as key in another Map.
public Pair<Double, Double> foo(...) {
// ...
Pair<Double, Double> range = Pair.of(minimum, maximum);
return range;
}
The big advantage of this class is, that the type you return exposes the contained types. So if you need to, you could return different types from a single method execution (without using a map or complicated inner class).
e.g. Pair<String, Double> or Pair<String, List<Double>>...
In simple situation, you just need to store min and max value from user input, your custom class will be ok than using Map, the reason is: in Java, a Map object can be a HashMap, LinkedHashMap or and TreeMap. it get you a short time to bring your data into its structure and also when you get value from the object. So in simple case, as you just described, just need to use your custom class, morever, you can write some method in your class to process user input, what the Map could not process for you.
I would say to look from perspective of the usage of a programming language. Let it be any language, there will be multiple ways to achieve the result (easy/bad/complicated/performing ...). Considering an Object oriented language like java, this question points more on to the design side of your solution.
Think of accessibility.
The values in a Map is kind of public that , you can modify the contents as you like from any part of the code. If you had a condition that the min and max should be in the range [-100 ,100] & if some part of your code inserts a 200 into map - you have a bug. Ok we can cover it up with a validation , but how many instances of validations would you write? But an Object ? there is always the encapsulation possibilities.
Think of re-use
. If you had the same requirement in another place of code, you have to rewrite the map logic again(probably with all validations?) Doesn't look good right?
Think of extensibility
. If you wanted one more data like median or average -either you have to dirty the map with bad keys or create a new map. But a object is always easy to extend.
So it all relates to the design. If you think its a one time usage probably a map will do ( not a standard design any way. A map must contain one kind of data technically and functionally)
Last but not least, think of the code readability and cognitive complexity. it will be always better with objects with relevant responsibilities than unclear generic storage.
Hope I made some sense!
The benefit is simple : make your code clearer and more robust.
The MaxAndMinValues name and its class definition (two fields) conveys a min and a max value but overall it makes sure that will accept only these two things and its class API is self explanatory to know how to store/get values from it.
While Map<String, Double> minAndMaxValuesMap conveys also the idea that a min and a max value are stored in but it has also multiple drawbacks in terms of design :
we don't know how to retrieve values without looking how these were added.
About it, how to name the keys we we add entries in the map ? String type for key is too broad. For example "MIN", "min", "Minimum" will be accepted. An enum would solve this issue but not all.
we cannot ensure that the two values (min and max) were added in (while an arg constructor can do that)
we can add any other value in the map since that is a Map and not a fixed structure in terms of data.
Beyond the idea of a clearer code in general, I would add that if MaxAndMinValues was used only as a implementation detail inside a specific method or in a lambda, using a Map or even an array {15F, 20F} would be acceptable. But if these data are manipulated through methods, you have to do their meaning the clearest possible.
We used custom class over Hashmap to sort Map based on values part
If I need to capture the name (first, middle and last) of a Person, I thought of the following possibilities:
Use a Map<String, String> name;
Use a separate Name class.
If I use a Map, I can store the names like this:
name.put("first", "xyz")
name.put("middle", "abc")
name.put("last", "nhf");
Then in the Person class:
class Person
{
Map<String, String> name;
//below write setter and getter for it.
}
If I use a Name class, I can store like this:
class Name
{
String first;
String middle;
String last;
//Below write setters and getters for them.
}
Then in the Person class:
class Person
{
Name name;
//below write setter and getter for it.
}
I wanted to know which one is a better way of doing and why. Also if there is any other better way of doing this.
Maps are great for flexibility. I.e., if you don't know exactly what keys you're going to have. E.g., if one person will have a Christian name, another will have a nickname and a third will have a paternal and maternal surnames, a Map may make sense. In your example, everybody has a first, middle and last name (although some of them may possibly be null?), so a map just adds redundant complication (as as noted here on the thread, memory consumption). Frankly, unless you have some special use for the entire Name as an object (e.g., using it as a key in a map), I'd just place three string members directly in the Person class.
This is entirely up to you -- there is no "best" answer here. It depends on how you are using the class.
Generally you do not want to hide things in a map like that. It makes more work to ensure things are correct. What if you accidentally add an incorrect key to the map? Your data structures could get out of whack easily with that method.
Personally, I would most likely just have the 3 values on the Person class directly and not bother with a Name class or a Map.
Once again, I am using words like "most likely" and "generally" because I do not know how the class is being used.
Creating a map is quite memory consuming, compared to creating a name class.
It's better to create the name class, (for one thing, less lines of code :P), mainly because it's less prone to be changed mid-run, unlike the map.
The entries in a map might be accidentally changed during runtime, which could cause problems. If the Name class doesn't have setters, then this can't happen.
Usually I'd love all my POJOs to be immutable (well, to contain only final fields as Java understands immutability). But with my current project, a constant pattern is that I need to change a single field from a POJO. Working with immutable POJO's in this scenario seems cumbersome.
How would you go about having POJO's with bunch of fields and for each field you should be able to say "please give me a copy of this POJO but with this one field changed"?
Big plus here would be something that I can use with composable Functions. "Start with this immutable pojo, then basically push it through bunch of UnaryOperators and give me back new immutable pojo".
Yes, that's a fairly common pattern - usually with a bunch of methods with a with prefix. Each with* method "changes" a single field, so you can have:
Person jon = new Person("Jon", "Skeet");
Person holly = jon.withFirstName("Holly"); // Holly Skeet
You can chain the calls together, too:
Person fred = jon.withAge(...).withFirstName("Fred").withJob(...);
Note that if you end up changing K fields in a POJO with N fields, you'll create K objects and need K * N assignments.
The implementation is usually just a matter of calling a big constructor with the existing field values and the new one:
public Person withFirstName(String newFirstName) {
return new Person(newFirstName, lastName, job, age, ...);
}
I've used the term "pseudo-mutator" for this kind of method - it's a method which sounds a bit like it's mutating something, but it's more like it's creating a clone, mutating the clone, then returning it to you in a "frozen" state.
Sorry for asking this, but i could really use a new PoV. Been sitting on it for days and can't wrap my head around it.
Basically, i have a Class Screw, whose object has attributes like length, material etc. It also saves the amount of screws and the weight this amount has.
So basically it sets Screw1 = 1cm, Steel, 200 Screws, 10kg (not like that of course, but for simplicities sake)
Those Screw objects are to be saved in a storage unit, sorted. So every combination of attributes gets it's own space to be saved in. It is limited by weight, so if you add 25kg of screws, you'd need two storage spaces, creating a new box to store them in.
It shall also be possible to take out screws, removing a storage space, if the weight of a box would drop below 0 and removing the remaining amount of screws from the new box.
public class Schraube {
private int schraubenArt,Material,SchraubenAnzahl, Entnahmeprotokoll;
private double durchmesser,laenge, gangHoehe,gaengigkeit,gewicht;
// lots of constructors and methods for calculations
}
I also had a storage class that would loop through all the possible combinations of Schraube and would then .add() them to an ArrayList, giving it maximum weight.
Now, how would you go about doing this? How do you add Stoagespaces if you go over weight 20kg? How would one do this efficiently without creating huge arrays of 561 spaces times 7?
I hope it's kinda clear what i am trying to do. Head hurts and i can't figure it out anymore.
My advise would be not to create a storage class since the Schraube class does not represent a singular entity but the properties of multiple entities. In this case you are setting the number of screws in a class that represents a screw. There are two solutions to this problem.
Create a getter method that calculates the number of storage spaces.
public int getNumberOfStorageSpaces(){
.... // Calculation logic
return numberOfStorageSpaces;
}
Or you can separate the type entity from quantity. In this case you would remove the SchraubenAnzahl property from the Schraube class, create another entity that encapsulates the type and quantity of screws called Schrauben. Then you would need a StorageSpace entity that represents a space and the quantity it can hold. Finally you would need an entity that represents the relationship between screws and storage spaces. This would be a more complex solution. To better understand the issue I recommend using an Entity Relationship Diagram to better illustrate the relationship between your entities.
I have a document with 15,000 items. Each item contains 6 variables (strings and integers). I have to copy all of these into some sort of two dimensional array, what the best way to do it?
Here are my ideas so far:
Make a GIANT 2D array or array list the same way you make any other array.
Pros: Simple Cons: Messy(would create a class just for this), huge amount of code, if I make a mistake it will be imposable to find where it is, all variables would have to be string even the ints which will make my job harder down the road
Make a new class with a super that takes in all the variables I need.
Create each item as a new instance of this class.
Add all of the instances to a 2D array or array list.
Pros: Simple, less messy, easier to find a mistake, not all the variables need to be strings which makes it much easier later when I don't have to convert string to int, a little less typing for me Cons: Slower? Will instances make my array compile slower? And will they make the over all array slow when I'm searching to items in it?
These ideas don't seem all to great :( and before I start the three week, five hour a day process of adding these items I would like to find the best way so I won't have to do it again... Suggestions on my current ideas or any new ideas?
Data example:
0: 100, west, sports, 10.89, MA, united
*not actual data
Your second options seems to be good. You can create a class containing all the items and create an array of that class.
You may use the following:
1. Read the document using buffered reader, so that memory issues will not occur.
2. Create a class containing your items.
3. Create a List of type you need and store the elements into it.
Let me know in case you face further problems.
If you already have the document with the 15000 * 6 items, in my experience you would be better served writing a program to use regex and parse it and have the output be the contents of the java array in the format you want. With such a parsing program in place, it will then also be very easy for you to change the format of the 15000 lines if you want to generate it differently.
As to the final format, I would have an ArrayList of your bean. By you text thus far, you don't necessarily need a super that takes in the variables, unless you need to have subtypes that are differentiated.
You'll probably run out of static space in a single class. So what I do is break up a big class like that into a file with a bunch of inner nested classes that each have a 64K (or less) part of the data as static final arrays, and then I merge them together in the main class in that file.
I have this in a class of many names to fix:
class FixName{
static String[][] testStrings;
static int add(String[][] aTestStrings, int lastIndex){
for(int i=0; i<aTestStrings.length; ++i) {
testStrings[++lastIndex]=aTestStrings[i];
}
return lastIndex;
}
static {
testStrings = new String[
FixName1.testStrings.length
+FixName2.testStrings.length
+FixName3.testStrings.length
+FixName4.testStrings.length
/**/ ][];
int lastIndex=-1;
lastIndex=add(FixName1.testStrings,lastIndex);
lastIndex=add(FixName2.testStrings,lastIndex);
lastIndex=add(FixName3.testStrings,lastIndex);
lastIndex=add(FixName4.testStrings,lastIndex);
/**/ }
}
class FixName1 {
static String[][] testStrings = {
{"key1","name1","other1"},
{"key2","name2","other2"},
//...
{"keyN","nameN","otherN"}
};
}
Create a wrapper (Item) if you have not already(as your question does not state it clearly).
If the size of the elements is fixed ie 1500 use array other wise use LinkedList(write your own linked list or use Collection).
If there are others operations that you need to support on this collection of items, may be further inserts, search( in particular) use balanced binary search tree.
With the understanding of the question i would say linked list is better option.
If the items have a unique property (name or id or row number or any other unique identifier) I recommend using a HashMap with a wrapper around the item. If you are going to do any kind of lookup on your data (find item with id x and do operation y) this is the fastest option and is also very clean, it just requires a wrapper and you can use a datastructure that is already implemented.
If you are not doing any lookups and need to process the items en masse in no specific order I would recommend an ArrayList, it is very optimized as it is the most commonly used collection in java. You would still need the wrapper to keep things clean and a list is far cleaner than an array at almost no extra cost.
Little point in making your own collection as your needs are not extremely specific, just use one that is already implemented and never worry about your code breaking, if it does it is oracles fault ;)