Intermediate Project 9 — Contact Book¶
Difficulty: Intermediate · Estimated effort: 12–16 hours · Prerequisites: Module 13 — Exception Handling, Module 14 — The STL with OOP, Module 5 — Operators and Static Members · Combines: persistence with a real round trip, indexed search, editing under an invariant, merge and deduplicate
This is one of the designated integration projects. It must use, explicitly and in writing: multiple classes · relationships between classes · encapsulation · inheritance or composition · polymorphism · the STL · exception handling.
No complete solution is provided. "Search" is where the design decisions concentrate, and they are yours to make.
1. Scenario¶
A department keeps a shared contact book of suppliers, staff and students. It holds names, several phone numbers and email addresses per person, a category, and a note. Entries are added and edited by hand, the file is sometimes hand-edited too, and duplicates creep in when the same person is entered twice with a different spelling.
The book must merge cleanly from two devices, which means deciding what "the same contact" means and making that decision survive a round trip.
2. Problem statement¶
Build a contact book: contacts with several contact methods each, categorised, searchable by name and by method, loaded from and saved to a documented text format, with duplicate detection on merge and precise, line-numbered errors for a bad file.
3. User requirements¶
- [ ] Add, edit and remove contacts; changes are validated before they land.
- [ ] Attach zero or more phone numbers and emails to a contact.
- [ ] Search by partial name, ignoring case, and by a contact method.
- [ ] List contacts by category.
- [ ] Merge another book file in, reporting duplicates found and how they were resolved.
- [ ] Save and reload, with the file readable and editable by hand.
4. Functional requirements¶
- [ ]
Contactwith a name, a category and a collection of contact methods. - [ ] A
ContactMethodabstraction or a value type with a kind — choose and justify; this is the polymorphism decision in the project. - [ ] A
Bookowning contacts, with add, edit, remove and search. - [ ] A documented file format supporting several methods per contact and an escape for the separator.
- [ ] Duplicate detection with a documented identity rule and a documented resolution rule.
- [ ] Errors for a malformed line, an empty name and an unknown category, each naming context.
- [ ] A failed merge leaves the book exactly as it was.
5. Non-functional requirements¶
- [ ] Search is not a full comparison of every field of every contact if you can index it — and if you do index it, you measure the difference and report it.
- [ ] Edits that would create an invalid contact are refused atomically.
- [ ] Round trip preserves names with the separator character in them.
- [ ] Contacts with zero methods are legal, and the format can express them.
- [ ] Builds warning-free with
g++ -std=c++17 -Wall -Wextra -Werror.
6. Suggested features¶
- A per-contact change history of the last few edits, capped and explained.
- Fuzzy duplicate detection (case- and space-insensitive names), with a false-positive example you accept.
- Import and export through the same interface with two formats.
- A
Bookview filtered by category that references rather than copies.
7. OOP concepts involved¶
| Concept | Required | Where it appears |
|---|---|---|
| Multiple classes | yes | Contact, contact methods, Book, search index, merge policy, error types |
| Relationships | yes | Book ◆ contacts; contact ◆ its methods; a search view ──> contacts it does not own |
| Encapsulation | yes | A contact cannot exist without a name; methods cannot be edited without revalidation |
| Inheritance or composition | yes | Method kinds as a hierarchy, or as a tagged value — the same decision the quiz engine faces, argued here |
| Polymorphism | yes | At least one operation dispatching on method kind (validation, normalisation or display) |
| The STL | yes | std::vector for order, std::map/std::set for indexes, algorithms for search and merge |
| Exception handling | yes | Malformed files and invalid edits throw distinct types; a failed merge rolls back |
8. Suggested design considerations¶
Define identity before writing merge. "Same person" might mean the same email, the same name and category, or the same phone number. Each choice has a failure mode, and the merge test is built from your rule. Write the rule down as a sentence and then implement that sentence.
Index, then justify. If you keep a case-folded name index, a measurement of search over ten thousand contacts is worth more than the assertion that it must be faster. If you do not index, say what the input size would have to be to make you.
Roll back the merge. Merging two books can fail halfway — a bad line, a conflicting edit. Build the result in a local book and move it into place, then prove with a test that the original is untouched after a failure.
Hand-editable means the format documents its own escaping. If a name contains the field separator, the file must say so unambiguously. Choose an escape rule and test it with a name containing it.
9. Minimum viable version¶
Contact with a name and one method, a Book with add/remove/list, and save/load for the
simple case. No search index, no merge.
10. Intermediate extension¶
Add multiple methods per contact, the category filter, case-insensitive partial-name search and the escape rule, then verify that a round trip preserves a name containing the separator and a contact with zero methods.
11. Advanced extension¶
Add the merge with duplicate detection and rollback, plus an indexed search with a measured comparison against the linear version. Then export in a second format behind the same interface and record which files the change touched.
12. Testing checklist¶
- [ ] A contact with no methods round-trips and is listed
- [ ] A name containing the separator round-trips through the documented escape
- [ ] Search is case-insensitive and matches substrings, including at the start and end
- [ ] Categories are listed in a documented order and an unknown category is refused
- [ ] Editing a name to empty is refused and changes nothing
- [ ] Removing a contact leaves the rest untouched and their order preserved
- [ ] Merging a book with itself reports every contact as a duplicate and changes nothing
- [ ] Merging a book with one bad line fails entirely and leaves the target book unchanged
- [ ] Duplicate resolution follows the documented rule for each tested combination
- [ ] An indexed search and a linear search return the same set for ten test queries
- [ ] Save → load → save produces identical files
13. Documentation checklist¶
- [ ] The identity rule for a contact, in one sentence
- [ ] The duplicate-resolution rules, in a table
- [ ] The file format, with escaping specified and an awkward example
- [ ] The measurement table for search, if you indexed
- [ ] One note answering: value type or hierarchy for contact methods, and why?
14. Self-evaluation rubric¶
| Criterion | Excellent looks like | Weight |
|---|---|---|
| Identity and merge | Identity defined, duplicates resolved by rule, rollback proven | 25% |
| Format design | Hand-editable, escaped, versioned, round-trip tested on awkward data | 25% |
| Search | Correct and, if indexed, measurably faster with numbers | 15% |
| Interface | Edits validated atomically; views reference instead of copying | 15% |
| Failure handling | Bad files and bad edits refused with context, nothing left half-done | 10% |
| Documentation | Rules, format and evidence written down | 10% |
Related: Intermediate projects · Project roadmap · All projects · Module 14 — The STL with OOP