From baf31ed58d8f663073b9686f707eb1dff6570660 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Sun, 14 Apr 2024 18:37:33 +0800 Subject: [PATCH 1/2] Add DG implementation details for sorting, birthday and priority Let's * Add implementation, UML diagrams and design considerations for sort. * Add implementation and UML for birthday and priority extensions to add and edit commands --- docs/DeveloperGuide.md | 74 +++++++++++++++++++ docs/diagrams/AddPersonObjectDiagram.puml | 23 ++++++ docs/diagrams/AddPersonSequenceDiagram.puml | 60 +++++++++++++++ docs/diagrams/SortPersonsObjectDiagram.puml | 29 ++++++++ docs/diagrams/SortPersonsSequenceDiagram.puml | 68 +++++++++++++++++ 5 files changed, 254 insertions(+) create mode 100644 docs/diagrams/AddPersonObjectDiagram.puml create mode 100644 docs/diagrams/AddPersonSequenceDiagram.puml create mode 100644 docs/diagrams/SortPersonsObjectDiagram.puml create mode 100644 docs/diagrams/SortPersonsSequenceDiagram.puml diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index f2b41a7e187..63f653158b0 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -189,6 +189,7 @@ The sequence diagram below shows the execution of `view 1` to view the details o * In this implementation, `DisplayClient` would simply be a `Person` set by `CommandResult`, similar to the current `feedbackToUser` implementation. * However, this means `DisplayClient` can only be set after a command, which does not allow us to set `DisplayClient` on application startup. + ### Adding notes to client feature The `remark` command allows users to add an optional note to a client. @@ -212,8 +213,38 @@ The `remark` command was implemented according to [Tutorial: Adding a command](h * While this might make it easier to type, it will also make fixing typos slower, like mentioned in the current behaviour. * It also means that a separate way of parsing has to be used, instead of `ArgumentMultimap`, deviating from other commands. + ### Sorting clients feature +The `sort` command allows users to sort the client list by a specified `sort criteria` that can be `name`, `priority` or `birthday`, and a `sort order` that can be `asc` or `desc`. + +#### Implementation + +The functionality to `sort` clients is implemented in the `SortCommand` class. The `SortCommandParser` class is responsible for parsing the user input and creating a `SortCommand` object. + +The `SortCommandParser` class parses the input arguments by storing the prefixes of their respective values in a `ArgumentMultimap` object, and create a new `SortCommand` object with the parsed `SortCriteria` and `SortOrder`. + +The `SortCommand` object then creates a `Comparator` object using `SortCriteria` and `SortOrder` objects, and communicates with the `Model` component to update the `Comparator` used to sort the list of persons. + +The `SortCommand` object does the following: +- `PersonComparator#getComparator(SortCriteria, SortOrder)` is used to get the `Comparator` object using the `SortCriteria` and `SortOrder`. +- `Model#updateSortPersonComparator(Comparator)` - Updates the `Comparator` object used to sort the list of persons in the `Model` component. +- `Model#setDisplayClientAsFirstInSortedFilteredPersonList()` - Updates the displayed client in the UI to the first client in the sorted list of persons. + +The following object diagram illustrates the above: + + +The following sequence diagram shows the `sort` operation: + + +#### Design Considerations + +In order to keep `ModelManager#filteredPersons` as an immutable `final` field, we have decided not to modify the `filteredPersons` directly. Instead, we do the following: +- we store the `Comparator` object in `ModelManager#personComparator`, which can be updated by `ModelManager#updateSortPersonComparator(Comparator)`. +- When a sorted list of persons is needed, we call `ModelManager#getSortedFilteredPersonList()` which returns a new sorted list of persons sorted using the `ModelManager#personComparator`. + +This way, the original order of `ModelManager#filteredPersons` is preserved, and we can get a sorted list of persons when needed. + ### Updating last met feature The last met feature allows users to keep track and update their last interaction with their clients. @@ -331,6 +362,49 @@ The following sequence diagram shows the addpolicy operation: ### Deleting policy feature +### Extensions to add command and edit command: Add birthday, edit birthday, add priority, edit priority features + +The add birthday and edit birthday features allow users to add and edit the birthday of a client. Birthdays support the birthday reminders feature. The birthday is stored in the `Birthday` class, which contains the birthday details such as day, month, and year. The `Birthday` class is part of the `Person` object in the `Model` component. + +The add priority and edit priority features allow users to add and edit the priority of a client. Priority supports the sort by priority feature, and helps optimise client management. The priority is stored in the `Priority` class, which contains the priority details such as priority value. The priority value are enumerated, and can be one of the following: LOW, MEDIUM, HIGH, VIP. The `Priority` class is part of the `Person` object in the `Model` component. + +#### Implementation + +The functionality to add and edit birthday and priority is implemented in the `AddCommand` and `EditCommand` classes. The `AddCommandParser` and `EditCommandParser` classes are responsible for parsing the user input and creating an `AddCommand` or `EditCommand` object respectively. + +The `AddCommandParser` and `EditCommandParser` classes parse the input arguments by storing the prefixes of their respective values in a `ArgumentMultimap` object, and create a new `AddCommand` or `EditCommand` object with the parsed birthday or priority, amongst other fields. + +The `AddCommand` and `EditCommand` objects then communicate with the `Model` component to add or edit the birthday or priority of the client. The `Model` component then updates the `Person` object with the new birthday or priority, amongst other fields. + +The `AddCommand` object then communicates with the `Model` component to add a person. +- `Model#addPerson(Person)` - Adds the new client to the existing client list. +- `Model#setDisplayClient(Person)` - Updates the displayed client in the UI to the client that has been added. + +The following object diagram illustrates the above: + + +The following sequence diagram shows the `add` operation: + + +More on birthday class +* Birthday is immutable and stores the day, month and year as a `LocalDate` object, as time is not relevant for birthday. +* The message constraints for birthday utilise the `DateUtil` common class to ensure that the date is valid and in the correct format. +* `DateUtil` class is used to validate (conforms to `DateUtil` date format and is parsable) and parse the string to a `LocalDate` object. `DateUtil` is also used to ensure that the date is not in the future. +* Refer to the `DateUtil` class for more information on the date format and parsing. + +More on priority class +* Priority is immutable and stores the priority value as a `PriorityValue` object, which is an enumerated type, to ensure that priority value is a valid type. +* The message constraints for priority utilise the `PriorityValue` enum class which should be responsible for the `toString()` logic for display. +* `PriorityValue` enum class is used to validate the priority value, which is responsible for the possible valid priority values. +* Refer to the `PriorityValue` enum class for more information on the priority values. + +More on priority value enum class +* `PriorityValue` is an enumerated type that contains the possible valid priority values: LOW, MEDIUM, HIGH, VIP. +* When parsing from a string and displaying as a string, the `PriorityValue` allows full form values (`low`, `medium`, `high`, `vip`) and short form values (`l`, `m`, `h`, `v`) to be used interchangeably. +* Parsing from a string to a `PriorityValue` object is case-insensitive, and is handled by `getPriority`. +* Obtaining the all available full form and short form of the `PriorityValue` object is handled by `getFullPriorities()` and `getShortPriorities()` respectively. +* The mapping of the full form strings and short form strings to the enum values is handled through `HashMap FULL_PRIORITY_MAP` and `HashMap SHORT_PRIORITY_MAP`, which has a constant time complexity. + ### \[Proposed\] Undo/redo feature #### Proposed Implementation diff --git a/docs/diagrams/AddPersonObjectDiagram.puml b/docs/diagrams/AddPersonObjectDiagram.puml new file mode 100644 index 00000000000..6c625282a3e --- /dev/null +++ b/docs/diagrams/AddPersonObjectDiagram.puml @@ -0,0 +1,23 @@ +@startuml +!include style.puml +skinparam objectFontColor white + +object ":AddCommand" as AddCommand LOGIC_COLOR +object ":AddCommandParser" as AddCommandParser LOGIC_COLOR +object ":AddressBookParser" as AddressBookParser LOGIC_COLOR +object ":Model" as Model MODEL_COLOR +object ":CommandResult" as CommandResult LOGIC_COLOR +object "toAdd:Person" as Person LOGIC_COLOR +object ":ArgumentMultimap" as ArgumentMultimap LOGIC_COLOR +object ":ParserUtil" as ParserUtil LOGIC_COLOR + +AddressBookParser --> AddCommandParser : calls +AddressBookParser --> AddCommand +AddCommandParser -> AddCommand +AddCommandParser --> ArgumentMultimap : instantiates +ParserUtil --> ArgumentMultimap : parses +AddCommand --> Person +AddCommand --> Model +AddCommand -right-> CommandResult : outputs +Model -right-> Person : Adds +@enduml diff --git a/docs/diagrams/AddPersonSequenceDiagram.puml b/docs/diagrams/AddPersonSequenceDiagram.puml new file mode 100644 index 00000000000..66d50ca8db2 --- /dev/null +++ b/docs/diagrams/AddPersonSequenceDiagram.puml @@ -0,0 +1,60 @@ +@startuml +!include style.puml +skinparam ArrowFontStyle plain + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant "a:AddCommand" as AddCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +end box +[-> LogicManager : execute(...) +activate LogicManager + +LogicManager -> AddressBookParser : parseCommand(...) +activate AddressBookParser + +create AddCommand +AddressBookParser -> AddCommand : AddCommand(...) +activate AddCommand + +AddCommand --> AddressBookParser +deactivate AddCommand + +AddressBookParser --> LogicManager : a +deactivate AddressBookParser + +LogicManager -> AddCommand : execute() +activate AddCommand + +AddCommand -> Model : addPerson(toAdd) +activate Model + +Model --> AddCommand +deactivate Model + +AddCommand -> Model : setDisplayClient(toAdd) +activate Model + +Model --> AddCommand +deactivate Model + +create CommandResult +AddCommand --> CommandResult +activate CommandResult + +CommandResult --> AddCommand +deactivate CommandResult + +AddCommand --> LogicManager : result +deactivate AddCommand +AddCommand -[hidden]-> LogicManager : result +destroy AddCommand + +[<--LogicManager +deactivate LogicManager +@enduml diff --git a/docs/diagrams/SortPersonsObjectDiagram.puml b/docs/diagrams/SortPersonsObjectDiagram.puml new file mode 100644 index 00000000000..73b92570331 --- /dev/null +++ b/docs/diagrams/SortPersonsObjectDiagram.puml @@ -0,0 +1,29 @@ +@startuml +!include style.puml +skinparam objectFontColor white + +object ":SortCommand" as SortCommand LOGIC_COLOR +object ":SortCommandParser" as SortCommandParser LOGIC_COLOR +object ":AddressBookParser" as AddressBookParser LOGIC_COLOR +object ":Model" as Model MODEL_COLOR +object ":CommandResult" as CommandResult LOGIC_COLOR +object "sortCriteria:SortCriteria" as SortCriteria LOGIC_COLOR +object "sortOrder:SortOrder" as SortOrder LOGIC_COLOR +object ":Comparator" as Comparator LOGIC_COLOR +object ":ArgumentMultimap" as ArgumentMultimap LOGIC_COLOR +object ":ParserUtil" as ParserUtil LOGIC_COLOR + +AddressBookParser --> SortCommandParser : calls +AddressBookParser --> SortCommand +SortCommandParser -> SortCommand +SortCommandParser --> ArgumentMultimap : instantiates +ParserUtil --> ArgumentMultimap : parses +SortCommand --> Model +SortCommand ---> SortCriteria : contains +SortCommand ---> SortOrder : contains +SortCommand --> Comparator : creates +SortCommand -right-> CommandResult : outputs +Comparator --> SortCriteria : uses +Comparator --> SortOrder : uses +Model --> Comparator : updates comparator to sort persons +@enduml diff --git a/docs/diagrams/SortPersonsSequenceDiagram.puml b/docs/diagrams/SortPersonsSequenceDiagram.puml new file mode 100644 index 00000000000..492b7678767 --- /dev/null +++ b/docs/diagrams/SortPersonsSequenceDiagram.puml @@ -0,0 +1,68 @@ +@startuml +!include style.puml +skinparam ArrowFontStyle plain + +box Logic LOGIC_COLOR_T1 +participant ":LogicManager" as LogicManager LOGIC_COLOR +participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR +participant "a:AddCommand" as AddCommand LOGIC_COLOR +participant ":CommandResult" as CommandResult LOGIC_COLOR +end box + +box Model MODEL_COLOR_T1 +participant ":Model" as Model MODEL_COLOR +participant "<>\nPersonComparator" as PersonComparator MODEL_COLOR +end box + +[-> LogicManager : execute(...) +activate LogicManager + +LogicManager -> AddressBookParser : parseCommand(...) +activate AddressBookParser + +create AddCommand +AddressBookParser -> AddCommand : AddCommand(...) +activate AddCommand + +AddCommand --> AddressBookParser +deactivate AddCommand + +AddressBookParser --> LogicManager : a +deactivate AddressBookParser + +LogicManager -> AddCommand : execute() +activate AddCommand + +AddCommand -> PersonComparator : getComparator(sortCriteria, sortOrder) +activate PersonComparator + +PersonComparator --> AddCommand : comparator +deactivate PersonComparator + +AddCommand -> Model : updateSortPersonComparator(comparator) +activate Model + +Model --> AddCommand +deactivate Model + +AddCommand -> Model : setDisplayClientAsFirstInSortedFilteredPersonList() +activate Model + +Model --> AddCommand +deactivate Model + +create CommandResult +AddCommand --> CommandResult +activate CommandResult + +CommandResult --> AddCommand +deactivate CommandResult + +AddCommand --> LogicManager : result +deactivate AddCommand +AddCommand -[hidden]-> LogicManager : result +destroy AddCommand + +[<--LogicManager +deactivate LogicManager +@enduml From 321c70eecd2711a7871d763ee6f958c83d4d2012 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Sun, 14 Apr 2024 19:14:37 +0800 Subject: [PATCH 2/2] Add minor fixes --- docs/DeveloperGuide.md | 14 ++++++-------- docs/diagrams/AddPersonObjectDiagram.puml | 9 +++++---- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 431d78ad389..dccf5781783 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -224,8 +224,6 @@ The functionality to `sort` clients is implemented in the `SortCommand` class. T The `SortCommandParser` class parses the input arguments by storing the prefixes of their respective values in a `ArgumentMultimap` object, and create a new `SortCommand` object with the parsed `SortCriteria` and `SortOrder`. -The `SortCommand` object then creates a `Comparator` object using `SortCriteria` and `SortOrder` objects, and communicates with the `Model` component to update the `Comparator` used to sort the list of persons. - The `SortCommand` object does the following: - `PersonComparator#getComparator(SortCriteria, SortOrder)` is used to get the `Comparator` object using the `SortCriteria` and `SortOrder`. - `Model#updateSortPersonComparator(Comparator)` - Updates the `Comparator` object used to sort the list of persons in the `Model` component. @@ -366,7 +364,7 @@ The following sequence diagram shows the addpolicy operation: The add birthday and edit birthday features allow users to add and edit the birthday of a client. Birthdays support the birthday reminders feature. The birthday is stored in the `Birthday` class, which contains the birthday details such as day, month, and year. The `Birthday` class is part of the `Person` object in the `Model` component. -The add priority and edit priority features allow users to add and edit the priority of a client. Priority supports the sort by priority feature, and helps optimise client management. The priority is stored in the `Priority` class, which contains the priority details such as priority value. The priority value are enumerated, and can be one of the following: LOW, MEDIUM, HIGH, VIP. The `Priority` class is part of the `Person` object in the `Model` component. +The add priority and edit priority features allow users to add and edit the priority of a client. Priority supports the sort by priority feature, and helps optimise client management. The priority is stored in the `Priority` class, which contains the priority details such as priority value. The priority value are enumerated, and can be one of the following: `LOW`, `MEDIUM`, `HIGH`, `VIP`. The `Priority` class is part of the `Person` object in the `Model` component. #### Implementation @@ -374,7 +372,7 @@ The functionality to add and edit birthday and priority is implemented in the `A The `AddCommandParser` and `EditCommandParser` classes parse the input arguments by storing the prefixes of their respective values in a `ArgumentMultimap` object, and create a new `AddCommand` or `EditCommand` object with the parsed birthday or priority, amongst other fields. -The `AddCommand` and `EditCommand` objects then communicate with the `Model` component to add or edit the birthday or priority of the client. The `Model` component then updates the `Person` object with the new birthday or priority, amongst other fields. +The `AddCommand` and `EditCommand` objects then communicate with the `Model` component to add or edit the birthday or priority of the client. The `Model` component then adds or edits the `Person` object with the new birthday or priority, amongst other fields. The `AddCommand` object then communicates with the `Model` component to add a person. - `Model#addPerson(Person)` - Adds the new client to the existing client list. @@ -386,20 +384,20 @@ The following object diagram illustrates the above: The following sequence diagram shows the `add` operation: -More on birthday class +More on `Birthday` class * Birthday is immutable and stores the day, month and year as a `LocalDate` object, as time is not relevant for birthday. * The message constraints for birthday utilise the `DateUtil` common class to ensure that the date is valid and in the correct format. * `DateUtil` class is used to validate (conforms to `DateUtil` date format and is parsable) and parse the string to a `LocalDate` object. `DateUtil` is also used to ensure that the date is not in the future. * Refer to the `DateUtil` class for more information on the date format and parsing. -More on priority class +More on `Priority` class * Priority is immutable and stores the priority value as a `PriorityValue` object, which is an enumerated type, to ensure that priority value is a valid type. * The message constraints for priority utilise the `PriorityValue` enum class which should be responsible for the `toString()` logic for display. * `PriorityValue` enum class is used to validate the priority value, which is responsible for the possible valid priority values. * Refer to the `PriorityValue` enum class for more information on the priority values. -More on priority value enum class -* `PriorityValue` is an enumerated type that contains the possible valid priority values: LOW, MEDIUM, HIGH, VIP. +More on `PriorityValue` enum class +* `PriorityValue` is an enumerated type that contains the possible valid priority values: `LOW`, `MEDIUM`, `HIGH`, `VIP`. * When parsing from a string and displaying as a string, the `PriorityValue` allows full form values (`low`, `medium`, `high`, `vip`) and short form values (`l`, `m`, `h`, `v`) to be used interchangeably. * Parsing from a string to a `PriorityValue` object is case-insensitive, and is handled by `getPriority`. * Obtaining the all available full form and short form of the `PriorityValue` object is handled by `getFullPriorities()` and `getShortPriorities()` respectively. diff --git a/docs/diagrams/AddPersonObjectDiagram.puml b/docs/diagrams/AddPersonObjectDiagram.puml index 6c625282a3e..ca0b3c8c8f4 100644 --- a/docs/diagrams/AddPersonObjectDiagram.puml +++ b/docs/diagrams/AddPersonObjectDiagram.puml @@ -7,9 +7,9 @@ object ":AddCommandParser" as AddCommandParser LOGIC_COLOR object ":AddressBookParser" as AddressBookParser LOGIC_COLOR object ":Model" as Model MODEL_COLOR object ":CommandResult" as CommandResult LOGIC_COLOR -object "toAdd:Person" as Person LOGIC_COLOR -object ":ArgumentMultimap" as ArgumentMultimap LOGIC_COLOR -object ":ParserUtil" as ParserUtil LOGIC_COLOR +object "toAdd:Person" as Person LOGIC_COLOR +object ":ArgumentMultimap" as ArgumentMultimap LOGIC_COLOR +object ":ParserUtil" as ParserUtil LOGIC_COLOR AddressBookParser --> AddCommandParser : calls AddressBookParser --> AddCommand @@ -19,5 +19,6 @@ ParserUtil --> ArgumentMultimap : parses AddCommand --> Person AddCommand --> Model AddCommand -right-> CommandResult : outputs -Model -right-> Person : Adds +Model -right-> Person : adds +Model --> Person : set client to display as @enduml