Closed thompsy closed 2 years ago
According to the previous implementation I declared a string field inside the Task class that a method could set it to "Done" when the user invoked that method.
The user chose the task by entering the task title. Then the method would search the list of tasks whether that task existed and if it did its string named "status" would be set to "Done". So the choice of the task will exploit a field from the task class.
Another way to identify uniquely a stored task is to create a static integer inside the TaskManager class and an int field inside the Task class. Whenever the user creates a new task the static integer could be incremented and its updated value stored in the int field of the new task. In this way each task will have a unique integer id which can be printed along with the title, the date and the time of the task so that the user can see which id corresponds to which task.
What approach do you suggest to follow?
Ok, there are two concerns here:
How do we store the task status data? Previously you were using a String
which could be set to "Done". Are there any drawbacks to this approach? Are there any other possibly approaches you could take here? Other data types that could be used? If so, what would the pros and cons of each approach be? Think about possible future extensibility too. What if we wanted to enable the user to mark tasks as "Waiting" or "Blocked" or something else...
How do we uniquely identify tasks? You've identified two reasonable possibilities here: using the title of the task or using a unique id. The next step is to think a bit about the pros and cons of each approach. Are there any cases where using the title wouldn't work? Are there any reasons why using a unique id wouldn't work? Think about the kind of data structures that each approach could use, are there any performance characteristics that might impact our choice?
A lot of software engineering is about understanding the different options and choosing the best one for the given context. There is very seldom a "correct" approach to solving something but often there are better and worse ones each with different trade-offs. It would be good for you to start developing this kind of thought process.
So, I suggest you have a think through the questions above and take a stab at writing out the pros and cons of each approach. This doesn't need to be perfect and it's likely there'll be things that you aren't aware of yet, but it's a good discipline to get into and develop!
If we print the size of a string on a C++ compiler it is 32 bytes, the size of an integer is 4 and the size of a char is 1 byte. In Java "a simple "ASCII" string can have different number of bytes in its representation, depending which encoding is used. That means each character in a string may not be represented always by one byte.".StaclkOverflow. Creating one field more per Task object raises the resources of memory consumed by the program.
Regarding the efficiency of data structures in "Thinking in Java", Bruce Eckel, on p.863-870 a program is executed which tests various linear data structures for various operations such as insertions and deletions of elements and for various sizes of elements they hold. The output of the time it takes for the operations to be completed also is printed and the performance of each data structure is analyzed.
For a list backed by an array the access of the list is very fast regardles of the size of the list for 10-10000 elements. For inserting elements in the middle of a list with an iterator that becomes very expensive for an ArrayList for 10000 elements while for a LinkedList the access is equally fast as for 100 elements and about 10 times faster than the ArrayList. "An ArrayList must create space and copy all its references forward during an insertion and this becomes expensive as the list gets bigger whereas a LinkedList only needs to link a new element and doesn't have to modify the rest of the list so the cost of the access remains constant and invariable with the list size.", p.869, "Thinking in Java", B. Eckel.
Conclusion: a LinkedList should be preferred for operations in the middle of the list otherwise an ArrayList can be used as a default list. A list backed by an array (produced by Arrays.asList()
) or an actual array can be used for fixed-size set of elements.
As for the issue the user may want to add different types of status to the tasks one method would be to provide an array of strings which will hold the type of status for a task, a method that will initialize a string of how the user wants to mark a task and another method and a HashMap that will create a key-value pair of a task title and a status.
How do you suggest me to go with the implementation of the complete method? Shall I go for the last implementation with a string field for the status of a task?
There's another option here that would be even better, an Enum
. This is ideal for these kind of situations where there is a list of possible states that are non-overlapping and known in advance. So, I suggest you create a Status
enum that captures a number of states. Probably, Open
, Done
and Blocked
would be fine for now. Blocked
represents a task that I can't do anything about yet e.g. I'm waiting for someone to give me more information or something. If we need to, we can expand on this later. Note that you'll want to add a new command line option to allow for tasks to be moved to a different state.
I suggest that you don't use the task title to uniquely identify them. There are several issues with this approach:
String
comparison is relatively slow!A better approach would be to use a unique Id number to refer to each task. There are several benefits to this:
TaskManager
can assign the Ids automatically so the user doesn't have to think about them.Map
to store the Task
s which allows for much more efficient lookup and avoids you needing to do any sorting of your current List<Task>
.So, what you need to do is:
id
field to the Task
TaskManager
keep track of the last id
it assigned or read in from an existing file. TaskManager
store the tasks in a Map
keyed by the new id
field.Enum
with the statuses and add that as a field to Task
id
and moves it to a different state.Hopefully that all makes sense, but if not do ask!
I have finished the implementation, I tested it with input and it is functional. I am checking for any points requiring potentially refactoring or correction. When I open the PR I will ask your opinion for some candidate points requiring refactoring in case they do not conform with the software design principles.
The current implementation allows a user to add and view tasks. It would also be useful for users to be able to mark tasks as "Done." The command line should look something like this:
task.sh --task XXX --done
This would mark a specific task
XXX
as complete. Note that when the users views the tasks completed tasks should still appear but should be clearly marked as "Done."You'll need to think a bit about how you're going to implement this. Specifically, how will you uniquely identify which task the user wants to complete?
I suggest you have a think and propose some possible solutions in this thread before you start implementing one of them.