After studying this code and completing the corresponding exercises, you should be able to,
- Apply Encapsulation
[LO-Encapsulation] - Implement a class
[LO-ImplementClass] - Follow the Single Responsibility Principle
[LO-SRP] - Handle Exceptions
[LO-Exceptions] - Use Inheritance to achieve code reuse
[LO-Inheritance] - Follow Interface Segregation Principle
[LO-ISP] - Use class-level members
[LO-ClassLevel] - Use Composition
[LO-Composition] - Use Association Classes
[LO-AssociationClass] - Use JUnit to implement unit tests
[LO-JUnit] - Use TDD
[LO-TDD] - Work in a 2KLoC code base
[LO-2KLoC]
Side reading: Code smell: Primitive Obsession - A case against using primitives instead of small objects for simple tasks
-
Assume the address is entered in the following format
a/BLOCK, STREET, UNIT, POSTAL_CODEe.g.a/123, Clementi Ave 3, #12-34, 231534 -
Split the
Addressclass as follows. Note: the filled diamond symbol ◆ means anAddressconsists ofBlock,Street, etc. -
Update the user guide and tests to match.
The exercise in the LO-ImplementClass section is somewhat related to SRP as well.
Here’s a slightly more difficult exercise.
-
TextUiclass has more than one responsibility. Try to extract out the responsibility of Formatting text for display (e.g. adding decorations) in to a separate class namedFormatter.
-
The current code does not handle the situation where the user accidentally makes the storage file read only while the AddressBook program is running. Use exceptions to handle that situation better. e.g. instead of crashing, the program can inform the user of the problem.
Note how the Command class contains some code that is reused by some of its child classes.
By defining *Command classes as child classes of Command, we have avoided having to duplicate those methods
in multiple *Command classes.
Note how the Person class implements the ReadOnlyPerson interface so that clients who don’t need write access to
Person objects can access Person objects through the ReadOnlyPerson interface instead.
-
Add a
Printableinterface as follows. -
OverridethegetPrintableStringin classesName,Phone,Email, andAddressso that each produces a printable string representation of the object. e.g.Name: John Smith,Phone: 12349862 -
Add the following method in a suitable place of some other class. Note how the method depends on the Interface.
/** * Returns a concatenated version of the printable strings of each object. */ String getPrintableString(Printable... printables){
The above method can be used to get a printable string representing a bunch of person details. For example, you should be able to call that method like this:
//p is a Person object return getPrintableString(p.getPhone(), p.getEmail(), p.getAddress());
Note how some of the variables and methods are declared static. That means they are class-level members
rather than instance-level members.
e.g. Main.VERSION, Name.EXAMPLE, Utils.isAnyNull(…)
-
Convert the
Parser::parseCommand(…)method (i.e. theparseCommand()method of theParserclass) to a class-level method. Note how this method can be either class-level or instance-level. -
Note how some instance-level methods, such as the
setTagsmethod of thePersonclass, cannot be converted to a class-level method. -
Add an instance-level member
int sequenceNumberand a class-level variableint nextSequenceNumberto thePersonclass. Using these two variables, ensure that eachPersonobject has a unique sequence number that indicates the order in whichPersonobjects were created. e.g.-
Adamis the firstPersonobject to be created. It is assigned sequence number 1. -
BenandCharlieare created next, and assigned 2 and 3 respectively. -
Benis deleted. -
Daisyis added next and is given sequence number 4.
-
Note the following examples of composition (filled diamond):
| Whole | Parts |
|---|---|
|
|
|
|
Contrast with these examples of aggregration (empty diamond):
| Container | Contained |
|---|---|
|
|
The current design does not have any association classes.
-
Assume the following:
-
There are commands to add and remove tags to a person in the address book.
-
When the AddressBook program exits, it should print out a list of all the tags added/deleted during that session. e.g.
+ Jake Woo [friend] - Jake Woo [colleague] + Jean Wong [client]
-
-
To support (ii) above, implement an Association Class called
Taggingas given in the diagram below. EachTaggingobject will represent an adding or deleting of a tag for a specific person that happened during that session.
Note how there are many test classes in this code base that uses JUnit to implement automated unit tests e.g. test/java/seedu/addressbook/parser/ParserTest.java class contains tests for the seedu.addressbook.parser.Parser class.
-
First, make sure you know how to run JUnit tests by running existing JUnit tests. Instructions are in the Developer Guide.
-
Next, add a test to
test/seedu/addressbook/common/UtilsTest.javato test theseedu.addressbook.common.Utils#isAnyNull(Object…)method.
It’s recommended you do [LO-JUnit] before attempting TDD.
-
Add the following method to the
Nameclass. Use the TDD technique to add the method. Commit after each step./** * Returns true if the other name is very similar to this name. * Two names are considered similar if ... */ public boolean isSimilar(Name other) { ... }
-
You may define 'similar' as you see fit. Make sure the definition covers scenarios where other name is
null, in a different case, in a different order, is a subset/superset, etc. e.g.John K SmithJohn K SMIThJohn SmithSmith, John K -
Don’t forget to refactor the method to improve its code quality at the end.





