|
|
- # Yhteystiedot ja osoitekirja 1/3
-
- Tämä harjoitus pohjautuu seuraavaan kahteen luokkaan sekä erikseen toteutettavaan `AddressBookApp`-luokkaan.
-
- **Contact-luokka:**
-
- ```
- // tiedosto Contact.java
-
- public class Contact {
-
- private String name;
- private String email;
- private String phone;
-
- public Contact(String name, String email, String phone) {
- this.name = name;
- this.email = email;
- this.phone = phone;
- }
-
- public String getName() {
- return this.name;
- }
-
- public String toString() {
- // Haluttu muoto: "Maija Meikäläinen (email: foo@bar.fi, phone: 5555)"
- return this.name + " (email: " + this.email + ", phone: " + this.phone + ")";
- }
- }
- ```
-
- **AddressBook-luokka:**
-
- ```
- // tiedosto AddressBook.java
-
- import java.util.ArrayList;
- import java.util.Comparator;
- import java.util.List;
- import java.util.stream.Collectors;
-
- public class AddressBook {
-
- private List<Contact> contacts;
-
- public AddressBook() {
- this.contacts = new ArrayList<>();
- }
-
- public boolean add(Contact newContact) {
- this.contacts.add(newContact);
- return true;
- }
-
- public Contact search(String keyword) {
- for (Contact current : this.contacts) {
- String name = current.getName();
- if (name != null && name.toLowerCase().contains(keyword.toLowerCase())) {
- return current; // palautetaan löytynyt arvo heti
- }
- }
- return null; // palautetaan null, jos ei löytynyt
- }
-
- @Override
- public String toString() {
- // TODO: toteuta tämä metodi. Metodin tulee muodostaa merkkijono,
- // joka sisältää kaikki yhteystiedot omilla riveillään.
- return "TODO";
- }
- }
- ```
-
- ## Ohjelman komentorivikäyttöliittymä
-
- Tehtävänä on tällä kertaa rakentaa uusi ohjelmaluokka `AddressBookApp`, joka mahdollistaa yhteystietojen käsittelyn `AddressBook` ja `Contact`-olioiden kanssa seuraavilla komennoilla:
-
- ```
- This is an address book application. Available commands:
- list
- help
- add <name>, <email>, <phone>
- search <name>
- exit
- ```
-
- Ohjelma tulee jakaa osiin siten, että vain `AddressBookApp`-luokka pyytää käyttäjältä syötteitä ja tulostaa tekstiä. `Contact` ja `AddressBook` ovat vain datan varastointia ja käsittelyä varten.
-
- ## Syötteiden pyytäminen
-
- Tämän sovelluksen käyttöliittymässä syötettä pyydettäessä ruudulle tulostetaan `>` -merkki syötteen odottamisen merkiksi:
-
- ```
- System.out.print("> ");
- ```
-
- Koska `>`-merkki tulostettiin `print` eikä `println`-metodilla, syöttää käyttäjä komentonsa samalle riville. Käyttäjän komento saattaa koostua yhdestä tai useasta osasta. Yhden sanan komentoja ovat esimerkiksi:
-
- ```
- > list
- ```
-
- ja
-
- ```
- > exit
- ```
-
- Moniosaisia komentoja ovat puolestaan esimerkiksi:
-
- ```
- > add Maija Meikäläinen, maija@example.com, +35850555556
- ```
-
- ```
- > search Matti
- ```
-
- ## Syötteiden lukeminen Scannerilla
-
- Syötteet kannattaa tässä sovelluksessa lukea kahdessa osassa. Ensin luetaan syötteen ensimmäinen sana ja sen jälkeen koko loppurivi:
-
- ```
- boolean running = true;
- while (running) {
- System.out.print("> ");
- String command = input.next();
- String theRest = input.nextLine().trim();
-
- // ... toimintalogiikka
- }
- ```
-
- Rivin ensimmäinen sana on aina komento (`command`), jonka perusteella valitaan mikä operaatio osoitekirjalle suoritetaan. Mahdollisesti annettua loppuriviä käytetään `add`- ja `search`-komentojen tapauksessa uuden yhteystiedon tietoina tai hakusanana.
-
- Jos käyttäjän syöte on `add Maija Meikäläinen, maija@example.com, +35850555556`, tulee muuttujien arvoiksi seuraavat:
-
- | command | theRest |
- |---------|----------------------------------------------------|
- | add | Maija Meikäläinen, maija@example.com, +35850555556 |
-
- `theRest`-muuttuja siis sisältää rivin koko loppuosan, joka `add`-komennon tapauksessa kannattaa pilkkoa String-luokan `split`-metodilla pilkkujen kohdalta:
-
- ```
- String[] parts = theRest.split(",");
-
- String name = parts[0].trim();
- String email = parts[1].trim();
- String phone = parts[2].trim();
- ```
-
- ## Ohjelman logiikan haarauttaminen
-
- Syötteen lukemisen jälkeen voidaan koodi haarauttaa joko Javan perusteista tutulla `if-else if-else`-ketjulla tai `switch case`-rakenteella:
-
- ```
- switch (command) {
- case "help":
- // tulosta ohje
- break;
- case "list":
- // tulosta osoitekirjan koko sisältö
- break;
- case "add":
- // käytä annettua nimeä, emailia ja puhelinnumeroa luodaksesi uuden yhteystiedon
- break;
- case "search":
- // etsi yhteystietoa ja tulosta se
- break;
- case "exit":
- // poistu ohjelmasta
- break;
- default:
- // tunnistamaton komento:
- System.out.println("Unknown command");
- break;
- }
- ```
-
- `Switch-case` -rakenne ei ole tässä välttämätön, mutta se sopii tilanteeseen hyvin ja sen opettelu voi olla hyödyksi sinulle myös myöhemmin. Koska ohjelman halutaan toimivan toistaiseksi ja kysyvän käyttäjän syötettä aina uudelleen, on edellä esitetyt syötteen kyselyt ja ehtorakenteet toteutettava jonkin toistorakenteen sisään.
-
- ## Käyttöliittymän ominaisuudet
-
- Sinun ei tarvitse toteuttaa kaikkia komentoja ohjelman ensimmäiseen versioon, vaan **toteuta ominaisuudet yksittäin sitä mukaan kun tarvitset niitä.**
-
- ### ADD
-
- add-komennon tulee lisätä yhdelle riville lisätyt yhteystiedot uutena oliona `AddressBook`-osoitekirjaan:
-
- ```
- > add Maija Meikäläinen, maija@example.com, +35850555556
- Added Maija Meikäläinen (email: maija@example.com, phone: +35850555556)
- ```
-
- ### SEARCH
-
- Jos annettu hakusana löytyy jostain osoitelistan yhteystiedosta, ohjelman tulee tulostaa kyseinen yhteystieto. Jos yhteystietoa ei löydy, tulostetaan siitä kertova viesti:
-
- ```
- > search Maija
- Maija Meikäläinen (email: maija@example.com, phone: +35850555556)
-
- > search Ville
- Ville does not match any contact.
- ```
-
- ### LIST
-
- Komennon `list` jälkeen ohjelman tulee tulostaa kukin yhteystieto omalla rivillään:
-
- ```
- > list
- Maija Meikäläinen (email: maija@example.com, phone: +35850555556)
- Matti Meikäläinen (email: matti@example.com, phone: +35850555555)
- ```
-
- ### HELP
-
- Käyttäjän syötettyä komennon `help` ohjelman tulee tulostaa sama ohjeteksti kuin ohjelman käynnistyksessä:
-
- ```
- This is an address book application. Available commands:
- list
- help
- add <name>, <email>, <phone>
- search <name>
- exit
- ```
-
- ### EXIT
-
- Käyttäjän kirjoittaessa syötteeksi "exit" ohjelman tulee tulostaa teksti "Bye!" ja lopettaa suorituksensa:
-
- ```
- > exit
- Bye!
- ```
-
- ### Esimerkki
-
- ```
- This is an address book application. Available commands:
- list
- help
- add <name>, <email>, <phone>
- search <name>
- exit
-
- > add Maija Meikäläinen, maija@example.com, +35850555556
- Added Maija Meikäläinen (email: maija@example.com, phone: +35850555556)
-
- > add Matti Meikäläinen, matti@example.com, +35850555555
- Added Matti Meikäläinen (email: matti@example.com, phone: +35850555555)
-
- > search Matti
- Matti Meikäläinen (email: matti@example.com, phone: +35850555555)
-
- > search Maija
- Maija Meikäläinen (email: maija@example.com, phone: +35850555556)
-
- > list
- Maija Meikäläinen (email: maija@example.com, phone: +35850555556)
- Matti Meikäläinen (email: matti@example.com, phone: +35850555555)
-
- > search Ville
- Ville does not match any contact.
-
- > exit
- Bye!
- ```
-
- **AddressBookApp.java
-
- ```
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Scanner;
-
- public class AddressBookApp {
-
- private static String welcomeText = "This is an address book application. Available commands:\n";
- private static String commandMenu = " list\n" +
- " help\n" +
- " add <name>, <email>, <phone>\n" +
- " search <name>\n" +
- " exit\n";
-
- // Keep here instead of translating to a local variable
- private static String inputCLIPrefix = "> ";
-
- // Keep added addressBook values during application runtime
- private static AddressBook addressBook = new AddressBook();
-
- public static void main(String[] args) {
-
- System.out.print(welcomeText + commandMenu);
-
- while (true) {
- runApp();
- }
- }
-
- private static void runApp() {
-
- Scanner inputPrompt = new Scanner(System.in);
- Object[] getInput = parseInput(inputCLIPrefix, inputPrompt);
-
- String inputCmd = String.valueOf(getInput[0]);
-
- // TODO Avoid risk of ClassCastException
- List<String> inputArgs = (ArrayList<String>)getInput[1];
- int argsCount = 3;
-
- switch(inputCmd) {
-
- case "list":
- System.out.println(addressBook.toString());
- break;
-
- case "help":
- System.out.print(welcomeText + commandMenu);
- break;
-
- case "add":
-
- // TODO Should this be checked in AddressBook.add method instead?
- if (inputArgs.size() != argsCount) {
- System.err.printf("Invalid count of input arguments (expected %d).\n", argsCount);
- break;
- }
-
- String name = String.valueOf(inputArgs.get(0));
- String email = String.valueOf(inputArgs.get(1));
- String phone = String.valueOf(inputArgs.get(2));
-
- Contact contact = new Contact(name, email, phone);
-
- // NOTE: Else condition not needed as 3 arguments is always passed
- // to this object method call
- if(addressBook.add(contact)) {
- System.out.printf("Added %s\n", contact.toString());
- }
-
- break;
-
- case "search":
-
- String searchTerm = String.valueOf(inputArgs.get(0));
- Contact match = addressBook.search(searchTerm);
-
- if (match == null) {
- System.out.printf("%s does not match any contact.\n", searchTerm);
- } else {
- System.out.println(match.toString());
- }
-
- break;
-
- case "exit":
- System.out.print("Bye!\n");
- System.exit(0);
-
- default:
- System.err.println("Command not found.");
- //break;
- }
- }
-
- private static Object[] parseInput(String prefix, Scanner inputRaw) {
-
- System.out.print(prefix);
- String inputR = inputRaw.nextLine();
-
- String command = inputR.split(" ")[0];
-
- String[] theRest = inputR.split(",");
- theRest[0] = theRest[0].replaceAll("^\\s*" + command + "\\s*","");
- List<String> arguments = new ArrayList<String>();
- for (int i = 0; i < theRest.length; i++) {
- arguments.add(theRest[i].trim());
- }
-
- Object[] parsedOutput = new Object[2];
- parsedOutput[0] = command;
- parsedOutput[1] = arguments;
-
- return parsedOutput;
- }
-
- }
- ```
-
- **AddressBook.java**
-
- ```
- import java.util.ArrayList;
- import java.util.List;
-
- public class AddressBook {
-
- private List<Contact> contacts;
-
- public AddressBook() {
- this.contacts = new ArrayList<>();
- }
-
- public boolean add(Contact newContact) {
- this.contacts.add(newContact);
- return true;
- }
-
- public Contact search(String keyword) {
- for (Contact current : this.contacts) {
- String name = current.getName();
- if (name != null && name.toLowerCase().contains(keyword.toLowerCase())) {
- return current; // palautetaan löytynyt arvo heti
- }
- }
- return null; // palautetaan null, jos ei löytynyt
- }
-
- @Override
- public String toString() {
- String returnString = "";
- for (Contact contact : this.contacts) {
- returnString += contact + "\n";
- }
- return returnString;
- }
- }
- ```
-
- **Contact.java**
-
- ```
- public class Contact {
-
- private String name;
- private String email;
- private String phone;
-
- // NOTE: This does not validate or check input String values
- // (Is name actually a name, email a valid email, and phone number an actual phone number?)
- public Contact(String name, String email, String phone) {
- this.name = name;
- this.email = email;
- this.phone = phone;
- }
-
- public String getName() {
- return this.name;
- }
-
- public String toString() {
- // Haluttu muoto: "Maija Meikäläinen (email: foo@bar.fi, phone: 5555)"
- return this.name + " (email: " + this.email + ", phone: " + this.phone + ")";
- }
- }
- ```
|