I am new to OOP, and still trying to wrap my head around just how encapsulated things should be. This question is about best practices, NOT about how to achieve functionality.
For an assignment, we are asked to make linked lists whose nodes contain two Strings: the name of the person spreading a disease, and the name of the person becoming infected. Each case of infection is only a record of who is involved, an infection doesn't actually do anything.
The assignment description suggests we add the two names as fields to the Nodes of the linked list. But my fledgling OOP-radar is booping, and I am unsure of whether or not I should instead create a nested Infection class within the node, or a top-level class of its own, which stores the two Strings.
So my internal conflict (and question) here is: at what point does an object become too simple to merit being an object anymore, while still keeping within the OOP-paradigm? Should I create an Infection class, or add data to the Node to keep it simple?
I would approach it the same way as Collections API does it: Create generic data structures that can hold any kind of objects and let the objects to define their internal structure/functionality.
The type could be generified, that would be the best practice.
Related
I want to do a SET or LIST without duplicates, but also want access your index. For exemple: setvariable.get(0).getName(). To access the object.
In java documentation is not recommended that use conditions to eliminate the duplicates in a list.
Then, how could i do?
I'm trying create an association between two objects, course and student. But i don't want that both to have duplicated data.
Thank you very much in advance!
Note:
I was trying to do a project but i was having problems of knowledge in association of OOP, and i come back for practice. At this time i'm doing exercise to practice OOP that i was having difficultly. Then i'm practicing OOP thinking ahead of the exercise implementing conditions that in fact dificult a real program, as duplicates. And how the teacher resolve all exercise with your index i was getting confused in keeping your index, but in fact seeing the explanations is not something necessary.
Solution: Use the SET because the index is not necessary in this case.
I was going to explain that Java doesn't have an "indexable" set class ... but then I looked at what you are actually trying to implement.
I going to assume that the association you are trying to implement is many-to-many. In the real world, a student may take many courses, and a course may be taken by many students. I assume your are trying to model that in your program.
The natural way to represent a (queryable) many-to-many association between two Java classes is using a pair of Map objects; e.g.
Map<Student, Set<Course>> enrolledCourses;
Map<Course, Set<Student>> enrolledStudents;
Depending on the kind of queries you need to perform, the maps could be HashMap or TreeMap. Each time you add or remove a relation between a Student and a Course you will need to update both Map objects.
Assuming that you maintain the maps correctly, there won't be any duplicate copies of either Student or Course objects.
On the other hand, if the association doesn't need to be queryable, you can get away with Set valued fields; e.g.
// In the Course class
Set<Student> enrolledStudents;
// In the Student class
Set<Course> enrolledCourses;
You could also use a List class and use contains to remove duplicates manually. That will lead to O(N) insertion and deletion operations, but that may be acceptable under normal real world assumptions. (Course enrollment numbers will typically be capped, and a student will only be allowed to enroll in a limited number of courses.)
Note that your idea of using list positions as some kind of identifier is not practical. When you remove an element in the middle of a list, all following elements in the list change positions. Positions are not stable in the long term.
You don't want that there are duplicates in the combinations or each list should not contain any duplicates?
For the second option you can check your list by using .contains before adding any additional element:
List<String> testList = null;
String element = null;
if (testList.contains(element)) {
testList.add(element);
}
This question already has answers here:
What does it mean to "program to an interface"?
(33 answers)
Closed 1 year ago.
I'm learning about the "coding to an interface to hide implementation details" design principle, and I'm confused over this idea. In my example, I have a WorkoutRoutine class that has a List of RoutineStep. By following the coding to an interface principle, my getWorkoutRoutine() method will return the List interface so that the implementation details of which list is used is hidden from the client.
What if I decide to change the implementation from a List of RoutineStep to an array of RoutineStep, won't disclosing the return type as List reveal to the client that a list was implemented and not an array, tree, graph, or any other data structure? How can I best encapsulate my data structure for holding a collection of RoutineStep, such that I can change the implementation of the data structure without the client code breaking if the List was changed to an array, tree, graph, etc?
public class WorkoutRoutine {
private List<RoutineStep> workoutRoutine;
public List<RoutineStep> getWorkoutRoutine() {
//What if I later decide to change the data structure from a List to an array, tree,
//graph, set, map. What approach should I take so that the client code doesn't break
//as they would have already coded to receive a List but after changing the
//implementation from a list to an array or any other data structure, their code would
//break.
}
}
The idea is to return a type that is as generic as possible but specific enough.
For example returning a LinkedList may be too specific - if the client starts using the getFirstmethod and you later on decide to return an ArrayList for performance reasons, the client code will break. Hence the principle of returning a more generic type, such as a List.
You could even go more generic and return a Collection - it may make sense if you don't think the client code will need to access the n-th position in the collection for example. But if you feel that accessing the n-th step of the routine (routine.get(n-1)) without having to iterate is an important feature, it means that Collection is too generic for your use case.
decide to change the implementation from a List of RoutineStep to an array of RoutineStep
The ArrayList is just what you would choose – a List implementation backed by an array structure.
Later, you may find that your app is more often inserting elements into the middle of the list rather than appending to the end. So you decide to switch your choice of List implementation from ArrayList to LinkedList. By having your method return an object of the more general interface List rather than the more specific concrete classes of ArrayList and LinkedList, your change from one class to the other does not break calling code.
By the way, we generally do not use array in Java where we expect to need the features and flexibility of a List or Set from the Java Collections Framework. We generally use arrays only where we need to conserve RAM because of deploying to constrained devices or we need maximum performance. Arrays were also used for their more convenient compact literals, but the new List.of and Set.of methods fill that need.
without the client code breaking if the List was changed to an array, tree, graph, etc?
If you are making such a massive change to the data structures of your app, then no amount of encapsulation will mask that change. At some point, your design changes may indeed break existing code.
Such breaking changes may be a natural part of the early stages in an emergent design. This is a normal part of our work. Later, in an evolved design, proper use of encapsulation with help protect against smaller changes having wider impact than is necessary, will make your codebase less brittle.
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.
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.