13
Tags:
java
Skrevet af
Bruger #4487
@ 07.12.2010
Indledning
Vi har indtil nu, lavet Java kode, hvor brugeren, ikke rigtigt havde noget at skulle have sagt. Alle vores elementer i vores ArrayList'er, har været for programmeret, og stod ikke til at kunne ændres. I denne del, skal vi se lidt på hvordan man kan få brugeren til at agere sammen med vores program. Vi kunne kalde programmet for en slags Tech-Support System, hvor brugeren, kan spørge om ting, og der bliver så givet et autogenereret svar til brugeren. Da dette er en helt så let sag, som det lyder, kan vi ikke undgå teorien, men frygt ej, da teorien er vigtig for at blive en god programmør.
Tech Support System
Systemet består af tre klasser, nemlig en
InputReader klasse, som har til formål at læse det input, som brugeren giver. Den næste klasse er en
Responder klasse, som har til formål at autogenerere et svar til brugeren, ud fra hans input. Den sidste klasse er en slags
controller klasse, som skal holde styr på input og output, og er derfor også vores 'Main' klasse. Denne klasse kunne vi kalde
TechSupportSystem. Lad os komme i gang med vores System.
HashSet og Scanner klasserne
Vi skal i gang med vores første klasse, som var
InputReader. Denne klasse for brug for at importere to forskellige klasser, fra vores Java bibliotek. De to klasser hedder henholdsvis
HashSet og
Scanner. Lad os starte med at finde ud af hvad klassen
HashSet, er for en størrelse.
Mini Opgave - Åben dit
Java Bibliotek, og find klassen
HashSet. Prøv nu at læse dokumentationen for klassen, og se om du kan finde ud hvad denne klasse kan bruges til. Hvis du alligevel ikke kan gennemskue hvad denne klasse kan bruges til, så kan du med fordel læse videre.
Som du måske har læst dig til, så er
HashSet klassen en kollektion klasse, akkurat ligesom vores
ArrayList var en kollektion. Forskellen er at hvor en
ArrayList var ordnet med et strikt indeks, så er
HashSet ikke ordnet. Dette betyder at kollektionen ikke bruger et såkaldt indeks, og kollektionen er derfor uordnet. Det gør at elementerne (altså Objekterne) i vores
HashSet kollektion, kan forekomme i forskellig rækkefølge/orden, hver eneste gang vi forsøger at gennemsøge vores kollektion.
HashSet kollektionen kræver som du måske har set i dokumentationen en generisk type. Da vi ved at en generisk type, kan være en hvilken som helst slags type, kan vi når vi skal bruge denne kollektion bruge typen
String, da vi gerne vil have kollektionen til at indeholde en masse 'ord', altså
Strings.
Nu ved vi lidt om kollektions klassen
HashSet, og vi kan gå videre til den anden klasse, som vi skal kende lidt til, nemlig
Scanner klassen.
Mini Opgave - Åben dit
Java Bibliotek, og find klassen
Scanner. Prøv nu at læse dokumentationen for klassen, og se om du kan finde ud af hvad denne klasse kan bruges til. Hvis du alligevel ikke kan gennemskue hvad denne klasse kan bruges til, så kan du med fordel læse videre.
Som du måske har læst dig til, så er
Scanner klassen en klasse, som kan læse/scanne input der er givet fra en bruger. Det er egentlig en meget simpel funktion, nemlig at den læser det input, som den for skudt i hovedet, hvorefter vi så kan bruge det input videre i vores program.
Videre til vores program
Nu da vi ved noget om to særdeles vigtige klasser, for dette system, så kan vi begynde på vores kodning. Vi skal nu have lavet vores klasse
InputReader, som sagt tidligere, skal læse vores input fra brugeren.
Opgave - Lav en ny mappe til dit system (kald den f.eks. SupportSystem), og lav så en klasse der hedder
InputReader. Giv klassen en konstruktør med en tom krop, og importer herefter vores to klasser, som vi skal benytte,
HashSet og
Scanner.
Vores kode ser nu således ud.
- import java.util.HashSet;
- import java.util.Scanner;
- /**
- * Klassen InputReader - Denne klasse kan læse input givet fra brugeren
- * og herefter gemme inputtet i en kollektion af typen HashSet.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class InputReader {
-
- /**
- * Konstruktør for objekter af klassen InputReader.
- */
- public InputReader()
- {
-
- }
-
- }
Det næste skridt er at vi skal have deklareret et felt, som kan indeholde et objekt af vores
Scanner klasse. Feltet skal selvfølgelig blive initialiseret i vores konstruktør, hvor vi laver et nyt objekt af klassen
Scanner. Du skal dog i
Scanner objektets konstruktør huske at angive en parameter, som skal være værdien
System.in, da den skal læse input fra vores kommandoprompt/tekst terminal. Vores kode ser nu ud som følgende.
- import java.util.HashSet;
- import java.util.Scanner;
- /**
- * Klassen InputReader - Denne klasse kan læse input givet fra brugeren
- * og herefter gemme inputtet i en kollektion af typen HashSet.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class InputReader {
-
- private Scanner reader;
-
- /**
- * Konstruktør for objekter af klassen InputReader.
- */
- public InputReader()
- {
- reader = new Scanner(System.in);
- }
-
- }
Herefter kan vi gå igang med den eneste metode, som vi skal have i denne klasse. Metodens formål er at læse input givet af brugeren, for derefter at splitte hvert eneste ord op, og derefter gemme hvert ord i vores kollektions klasse
HashSet. Den vil herefter returnere kollektionen af alle de ord brugeren har indtastet i hans/hendes sætning, som vi så kan bruge i vores andre klasser i programmet.
Udfordrings Opgave - Lav denne nye accessor metode, som skal være public. Datatypen skal være
HashSet med den generiske type
String, da denne kollektion skal kunne indeholde tekststykker, og i dette tilfælde enkelte ord. Kald metoden for
getInput, og lad kroppen til denne metode være tom for nu. Vores kode ser nu således ud.
- import java.util.HashSet;
- import java.util.Scanner;
- /**
- * Klassen InputReader - Denne klasse kan læse input givet fra brugeren
- * og herefter gemme inputtet i en kollektion af typen HashSet.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class InputReader {
-
- private Scanner reader;
-
- /**
- * Konstruktør for objekter af klassen InputReader.
- */
- public InputReader()
- {
- reader = new Scanner(System.in);
- }
-
- /**
- * Denne metode læser input fra brugeren, hvorefter den 'splitter' alle ordene for sig
- * og herefter gemmer hvert enkelt ord i vores kollektion HashSet.
- * @return En kollektion af Strings indeholdene hvert enkelt ord fra brugerens input.
- */
- public HashSet<String> getInput()
- {
-
- }
-
- }
Nu til metodens indhold. Det første vi skal gøre er at læse/scanne brugerens input, som han/hun har skrevet på linjen i vores kommandoprompt. Hvis du ikke allerede vidste det, kan vi se i under metoderne for klassen
Scanner i vores Java Bibliotek, at der er en metode, som hedder
nextLine(). Denne metode scanner/læser altså linjen som brugeren har indtastet, og returnerer herefter en
String værdi med brugerens input. Resultatet, som denne metode giver os, gemmer vi en en lokal variabel, som har datatypen
String. Variablen kunne vi f.eks. kalde inputLine. Vores metode ser nu således ud.
- /**
- * Denne metode læser input fra brugeren, hvorefter den 'splitter' alle ordene for sig
- * og herefter gemmer hvert enkelt ord i vores kollektion HashSet.
- * @return En kollektion af Strings indeholdene hvert enkelt ord fra brugerens input.
- */
- public HashSet<String> getInput()
- {
- String inputLine = reader.nextLine();
- }
Da brugerens input aldrig er helt til at forudsige, kan der nemt ske fejl. Det kunne være at brugeren i starten eller måske i slutningen kom til at skrive et mellemrum. mellemrum er usynlige karakterer, for det menneskelige øje, men for computeren betyder det en stor del. Det kunne også være at brugeren startede sætningen, eller måske skrev et ord med nogle store bogstaver ind i mellem, her ville vi heller ikke kunne læse ordet korrekt, da computere ikke er så smart indrettede, så de kan ikke skelne imellem store og små bogstaver. Heldigvis er der nogle programmører, som har løst disse problemer for os. Da vores lokale variabel
inputLine er af datatypen
String, kan vi benytte 2 fremragende metoder fra klassen
String, til netop at løse disse to problemstillinger. Den første metode hedder
trim(), og fjerner mellemrummet i starten og slutningen af ens
String, så vi ikke kommer ud for sådan et problem. Den anden metode hedder
toLowerCase(), og laver simpelthen hele vores
String om til små bogstaver, så selvom vores bruger skriver store bogstaver i sætningen, vil computeren sagtens kunne læse dette, da alle bogstaverne bliver genereret til små bogstaver.
Mini Opgave - Brug nu dot notation til at kalde henholdsvis
trim() metoden og
toLowerCase() metoden i din lokale variabel
inputLine. Husk at tildele det til den lokale variabel
inputLine igen, så vi stadig har alle metoderne i vores lokale variabel (brug en tildelings sæting 'Assignment Statement'). Når opgaven er løst, tjek koden med min nedenunder.
- /**
- * Denne metode læser input fra brugeren, hvorefter den 'splitter' alle ordene for sig
- * og herefter gemmer hvert enkelt ord i vores kollektion HashSet.
- * @return En kollektion af Strings indeholdene hvert enkelt ord fra brugerens input.
- */
- public HashSet<String> getInput()
- {
- //Scan linjen, og 'trim' herefter linjen og lav det hele til små bogstaver.
- String inputLine = reader.nextLine();
- inputLine = inputLine.trim();
- inputLine = inputLine.toLowerCase();
- }
Herefter skal vi 'splitte' hvert ord fra hindanden, så vi for opdelt sætningen til enkelte ord. Måden man kan splitte en sætning ad på, er ved at benytte metoden
split(), også fra klassen
String. Metoden
split() kræver kun en parameter, nemlig en String, som angiver hvornår metoden skal splitte sætningen ad. Metodens parameter kunne f.eks. være
" ". Metoden vil nu hver eneste gang den møder 'et mellemrum' i vores sætning lave et split af sætningen, og da vi i normal tekst kun laver et mellemrum mellem hvert ord, vil denne funktion være perfekt.
Udfordrings Opgave - Lav en lokal variabel som kan indholde et fikseret
Array med typen
String. Kald
Array'et for f.eks.
wordArray. Denne lokale variabel initialisere du til at indeholde din variabel
inputLine, som bruger dot notation til vores
split() metode. Husk at parameteren i metoden
split(), skal være
" ". Når opgaven er fuldført, så tjek din kode med min.
- /**
- * Denne metode læser input fra brugeren, hvorefter den 'splitter' alle ordene for sig
- * og herefter gemmer hvert enkelt ord i vores kollektion HashSet.
- * @return En kollektion af Strings indeholdene hvert enkelt ord fra brugerens input.
- */
- public HashSet<String> getInput()
- {
- //Scan linjen, og 'trim' herefter linjen og lav det hele til små bogstaver.
- String inputLine = reader.nextLine();
- inputLine = inputLine.trim();
- inputLine = inputLine.toLowerCase();
-
- //Split sætningen, og læg hvert ord ind i et array.
- String[] wordArray = inputLine.split(" ");
- }
Herefter skal vi lave et nyt objekt af vores
HashSet, og lægge det endnu en lokal variabel med datatypen
HashSet<String>. Vi skal herefter køre en løkke som automatisk tilføjer hvert enkelt ord til vores
HashSet kollektion.
For Each Løkken
Løkken som vi skal bruge til denne opgave hedder en
for each løkke, og er så smart indrettet at den hverken behøver en betingelse og et tællerskridt/forøgelse. Løkkens signatur/header ser således ud teoretisk -
for (Datatype lokal variabels navn : variabel/felt med vores kollektion) - Den første del er den del, som står før kolon tegnet ( : ), og den del laver en lokal variabel, som kan indeholde objekter af den datatype, som er i vores kollektion. Da vores
HashSet kollektion skal kunne indeholde data af typen
String, skal denne lokale variabel selvfølgelig også være af typen
String. variablens navn er bare et vilkårligt navn, og det kunne i vores tilfælde være navnet word, da vores kollektion skal kunne indeholde ord fra brugerens input, som nu er gemt i vores array
wordArray. Delen efter vores kolon, er den del, som skal kunne indeholde vores kollektion, altså hvilken kollektion skal denne løkke lede/undersøge sig igennem. I vores tilfælde skal løkken gennemsøge kollektionen i vores
wordArray, da den jo skal finde hvert enkelt ord. vores løkkes signatur ser nu således ud -
for (String word : wordArray) - og med menneskelige ord, kunne man sige at for hver (
for each) word med typen
String, i vores kollektion
wordArray, skal den køre løkken. Vores metode ser nu således ud, bemærk at løkkens krop stadig er tom.
- /**
- * Denne metode læser input fra brugeren, hvorefter den 'splitter' alle ordene for sig
- * og herefter gemmer hvert enkelt ord i vores kollektion HashSet.
- * @return En kollektion af Strings indeholdene hvert enkelt ord fra brugerens input.
- */
- public HashSet<String> getInput()
- {
- //Scan linjen, og 'trim' herefter linjen og lav det hele til små bogstaver.
- String inputLine = reader.nextLine();
- inputLine = inputLine.trim();
- inputLine = inputLine.toLowerCase();
-
- //Split sætningen, og læg hvert ord ind i et array.
- String[] wordArray = inputLine.split(" ");
-
- //Deklarer og initialiser et nyt HashSet, så den er klar.
- HashSet<String> words = new HashSet<String>();
-
- //For each løkken gennemsøger nu wordArray for alle de enkelte ord, og lægger dem ind i vores HashSet kollektion.
- for (String word : wordArray)
- {
-
- }
- }
Vores løkke skal nu lægge de elementer vi får ud af vores kollektion
wordArray ind i vores kollektion, som jeg i mit eksempel har kaldt
words, som jo var af typen
HashSet. kollektions klassen
HashSet har en metode der hedder
add(), som lægger et objekt ind i vores
HashSet. Objekterne der skulle lægges ind var jo vores
word, som jo heldigvis for os er af typen
String, da vores
HashSet kun kan indeholde objekter af typen
String. Så vi bruger dot notation til at kalde metoden add, og giver metoden
word som parameter, da vores første del i løkkens signatur var en lokal variabel med navnet word, som er her alle de enkelte ord havner.
- /**
- * Denne metode læser input fra brugeren, hvorefter den 'splitter' alle ordene for sig
- * og herefter gemmer hvert enkelt ord i vores kollektion HashSet.
- * @return En kollektion af Strings indeholdene hvert enkelt ord fra brugerens input.
- */
- public HashSet<String> getInput()
- {
- //Scan linjen, og 'trim' herefter linjen og lav det hele til små bogstaver.
- String inputLine = reader.nextLine();
- inputLine = inputLine.trim();
- inputLine = inputLine.toLowerCase();
-
- //Split sætningen, og læg hvert ord ind i et array.
- String[] wordArray = inputLine.split(" ");
-
- //Deklarer og initialiser et nyt HashSet, så den er klar.
- HashSet<String> words = new HashSet<String>();
-
- //For each løkken gennemsøger nu wordArray for alle de enkelte ord, og lægger dem ind i vores HashSet kollektion.
- for (String word : wordArray)
- {
- words.add(word);
- }
- }
Til sidst skal vi bare returnere noget. Husk at vi jo lavede en accessor metode, og accessor metoder returnerer altid noget. Det vi gerne vil returnere med denne metode, var jo vores
HashSet kollektion med de enkelte ord fra brugerens input lagt i. Vores
HashSet kollektion lå jo i den lokale variabel
words, som vi med løkken lige har lagt elementer i. så vores return statement ser således ud -
return words; - og vores metode ser nu således ud.
- /**
- * Denne metode læser input fra brugeren, hvorefter den 'splitter' alle ordene for sig
- * og herefter gemmer hvert enkelt ord i vores kollektion HashSet.
- * @return En kollektion af Strings indeholdene hvert enkelt ord fra brugerens input.
- */
- public HashSet<String> getInput()
- {
- //Scan linjen, og 'trim' herefter linjen og lav det hele til små bogstaver.
- String inputLine = reader.nextLine();
- inputLine = inputLine.trim();
- inputLine = inputLine.toLowerCase();
-
- //Split sætningen, og læg hvert ord ind i et array.
- String[] wordArray = inputLine.split(" ");
-
- //Deklarer og initialiser et nyt HashSet, så den er klar.
- HashSet<String> words = new HashSet<String>();
-
- //For each løkken gennemsøger nu wordArray for alle de enkelte ord, og lægger dem ind i vores HashSet kollektion.
- for (String word : wordArray)
- {
- words.add(word);
- }
-
- //Returnering af vores HashSet kollektion med de enkelte ord i.
- return words;
- }
Nu er vores klasse
inputReader færdig, og vi kan gå i gang med klassen
Responder, som har til formål at returnere et autogenereret svar til brugeren.
Responder klassen
Vi skal nu lave en klasse som skal generere diverse automatiske svar, som brugeren kan få i henhold til hvilket spørgsmål han indtaster som input.
Opgave - Lav nu en ny klasse i vores
SupportSystem, som hedder
Responder. Giv den en tom konstruktør, og importer disse klasser -
HashSet, ArrayList og Random - Din kode skulle nu gerne se således ud.
- import java.util.HashSet;
- import java.util.ArrayList;
- import java.util.Random;
- /**
- * Klassen Responder - Denne klasse har til formål at autogenerere nogle svar, som sendes
- * til brugeren i henhold til hans spørgsmål, som kom via et input.
- * Inputtet er præsenteret for Responder klassen, som en kollektion af ord (words), som
- * vi så kan gå igennem for at finde nogle nøgleord. Hvis et nøgleord findes, vil vi kunne
- * generere et automatisk svar til det givne nøgleord, så bruegren for et så godt svar som muligt.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class Responder {
-
- /**
- * Konstruktør for objekter af klassen Responder.
- */
- public Responder()
- {
-
- }
-
- }
Faktisk er vores klasse ikke helt klar, da vi skal importere to ting mere til vores klasse.
Iterator og HashMap
De to ting vi skal importere yderligere til vores
Responder klasse er
Iterator og
HashMap.
Mini Opgave - Åben dit
Java Bibliotek, og find
Iterator. Læs nu dokumentationen for
Iterator, og find ud af hvilke metoder den har. Når du har gjort dette, så læs videre.
En
iterator kan under en gennemsøgning af en kollektion stoppe op midt i kollektionen og ændre på indholdet. Dette kan også gøres uden en
Iterator, men processen med en
Iterator er langt bedre og nemmere. Som du måske har lagt mærke til står der ikke
class Iterator<E> som overskrift, men derimod
Interface Iterator<E>. Jeg vil ikke gå i detaljer med et interface lige nu, men det du skal vide er at dette satdig er en slags klasse, som alle andre, men det er også en speciel klasse. Ellers skal du ikke tænke mere over det, da det i denne sammenhæng ikke betyder så meget lige nu. Vi kan se at en
Iterator har tre forskellige metoder. Den første hedder
hasNext() og returnerer en boolean værdi (sand eller falsk). Den returnerer sandt, hver eneste gang der er et objekt mere i vores kollektion. Den anden metode hedder
next() og er den metode, som henter vores objekt fra kollektionen som vores
hasNext() metode lige har sagt var der. Den sidste metode hedder
remove(), og er den metode, som kan fjerne et givent objekt fra kollektionen. Med den viden i baghånden, kan vi gå videre til vores
HashMap klasse.
En
HashMap er en anden slags kollektions klasse, ligesom
ArrayList og
HashSet. Nu kan du jo tænke at hvorfor skal vi kende endnu en kollektions klasse, når vi allerede kender disse 2, som fungerer helt aldeles udmærket?
Mini Opgave - Åben dit
Java Bibliotek, og find klassen
HashMap. Læs nu dokumentationen for denne klasse, og gennemgå nogle af metoderne i denne klasse. Kan du finde ud af hvilke metoder, som man skal bruge til at lægge ting ind i kollektionen, og hvilken man skal bruge for at hente ting fra kollektionen. Når du har læst dokumentationen, så gå videre og jeg kan prøve at forklare dig hvad et
HashMap egentlig gør.
Et
HashMap er en speciel kollektion, som akkurat ligesom et
HashSet ikke har et indeks til sine objekter. Objekterne gemmes altså i en ikke ordnet kollektion, men det er ikke engang det bedste ved et
HashMap. Det bedste ved et
HashMap er at hvor man kun kunne gemme et objekt i hvert rum/indeks i en
ArrayList eller et
HashSet, kan vi i et
HashMap gemme to objekter i samme rum. Den bedste måde at sammenligne et
HashMap med virkeligheden på, er ved at tænke på en telefonbog. I en telefonbog, står der en masse telefonnumre, og til hvert telefonnummer er knyttet et specifikt navn, på det enkelte telefonnummer. Vi kan så slå op i telefonbogen og finde et specifikt navn, for derefter at få fat i telefonnummeret. Et
HashMap fungerer på akkurat samme måde. Et
HashMap skal nemlig bruge to generiske typer, hvor dan første type er en
key, og den næste er en
value. Vores
key i telefonbog eksemplet er det navn vi leder efter i telefonbogen. Det navn, har så en specifik
value, som er telefonnummeret. Vi kan så bruge metoderne
put() til at lægge indhold ind i vores
key og
value rum. Metoden til at hente en value hedder så
get(), og parameteren i metoden er den specifikke
key som er angivet. Det betyder så også at vores
key i et
HashMap aldrig må være ens, da den jo så ikke ved hvilken
value den skal hente.
Tilbage til koden
Nu har vi fået noget mere vigtig information, som vi skal bruge i vores
Responder klasse. Lad os først importere vores
Iterator og
HashMap til klassen. Herefter skal vi deklarere tre felter i klassen, hvor den første skal kunne indeholde en
ArrayList, som har den generiske type
String. Det andet felt skal kunne indeholde data af typen
HashMap, som har de to generiske typer
String som
key og
String som
value. Det tredje felt skal kunne indeholde data af typen
Random. Vores kode ser nu således ud.
- import java.util.HashSet;
- import java.util.ArrayList;
- import java.util.Random;
- import java.util.Iterator;
- import java.util.HashMap;
- /**
- * Klassen Responder - Denne klasse har til formål at autogenerere nogle svar, som sendes
- * til brugeren i henhold til hans spørgsmål, som kom via et input.
- * Inputtet er præsenteret for Responder klassen, som en kollektion af ord (words), som
- * vi så kan gå igennem for at finde nogle nøgleord. Hvis et nøgleord findes, vil vi kunne
- * generere et automatisk svar til det givne nøgleord, så bruegren for et så godt svar som muligt.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class Responder {
-
- private ArrayList<String> defaultResponses;
- private HashMap<String, String> responseMap;
- private Random randomGenerator;
-
- /**
- * Konstruktør for objekter af klassen Responder.
- */
- public Responder()
- {
-
- }
-
- }
Mini Opgave - Initialiser nu vores nye felter med objekter af den type data som de kan indeholde. Initialiser dem som altid i vores konstruktør. Når opgaven er udført, så tjek din kode med min.
- import java.util.HashSet;
- import java.util.ArrayList;
- import java.util.Random;
- import java.util.Iterator;
- import java.util.HashMap;
- /**
- * Klassen Responder - Denne klasse har til formål at autogenerere nogle svar, som sendes
- * til brugeren i henhold til hans spørgsmål, som kom via et input.
- * Inputtet er præsenteret for Responder klassen, som en kollektion af ord (words), som
- * vi så kan gå igennem for at finde nogle nøgleord. Hvis et nøgleord findes, vil vi kunne
- * generere et automatisk svar til det givne nøgleord, så bruegren for et så godt svar som muligt.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class Responder {
-
- private ArrayList<String> defaultResponses;
- private HashMap<String, String> responseMap;
- private Random randomGenerator;
-
- /**
- * Konstruktør for objekter af klassen Responder.
- */
- public Responder()
- {
- defaultResponses = new ArrayList<String>();
- responseMap = new HashMap<String, String>();
- randomGenerator = new Random();
- }
-
- }
Nu skal vi have lavet nogle metoder i vores
Responder klasse. De metoder vi skal bruge er nogle metoder, som fylder vores
ArrayList og
HashMap med nogle autogenerede svar. Vi skal have en metode, som udsender et vilkårligt svar hvis ikke nøgle af de nøgleord, som vi laver om lidt findes. Til sidst skal vi lave en metode, som returnerer det autogenerede svar, som vi vil give til brugeren.
Lad os begynde på de to første og letteste metoder. Nemlig de metoder, som skal udfylde vores
ArrayList og
HashMap med objekter, i dette tilfælde objekter af typen
String.
Udfordrings Opgave - Lav en mutator metode, som er private, der hedder fillDefaultResponses(). Metoden skal lægge
String objekter ind i vores
ArrayList kaldet
defaultResponses. Tænk over nogle 'standard' svar, som passer til alle typer af spørgsmål, og som ikke rigtig siger noget - et eksempel kunne være
Det lyder underligt, kan du beskrive problemet yderligere?. Når du har lavet denne metode, så sammenlign din kode med min.
- import java.util.HashSet;
- import java.util.ArrayList;
- import java.util.Random;
- import java.util.Iterator;
- import java.util.HashMap;
- /**
- * Klassen Responder - Denne klasse har til formål at autogenerere nogle svar, som sendes
- * til brugeren i henhold til hans spørgsmål, som kom via et input.
- * Inputtet er præsenteret for Responder klassen, som en kollektion af ord (words), som
- * vi så kan gå igennem for at finde nogle nøgleord. Hvis et nøgleord findes, vil vi kunne
- * generere et automatisk svar til det givne nøgleord, så bruegren for et så godt svar som muligt.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class Responder {
-
- private ArrayList<String> defaultResponses;
- private HashMap<String, String> responseMap;
- private Random randomGenerator;
-
- /**
- * Konstruktør for objekter af klassen Responder.
- */
- public Responder()
- {
- defaultResponses = new ArrayList<String>();
- responseMap = new HashMap<String, String>();
- randomGenerator = new Random();
- }
-
- /**
- * Denne metode udfylder vores ArrayList med nogle defaultResponses.
- */
- private void fillDefaultResponses()
- {
- defaultResponses.add("Det lyder underligt, kan du beskrive problemet yderligere?");
- defaultResponses.add("Det lyder interessant, fortael mig venligst mere.");
- defaultResponses.add("Din losning på problemet, er forklaret i manualen.");
- defaultResponses.add("Jeg forstår dig ikke helt, kunne du eventuelt uddybe problemet mere?");
- }
-
- }
Nu har vi udfyldt vores
ArrayList med nogle
defaultResponses så at sige, altså nogle svar, som skal bruges når vi ikke kan finde et nøgleord fra vores
HashMap, som skal laves nu.
Udfordrings Opgave - Lav nu en ny mutator metode, som er private, og hedder fillResponseMap(). Metoden skal lægge
keys og
values ind i vores
HashMap, som er gemt i feltet
responseMap. Brug metoden
put() fra
HashMap klassen til at lægge et
key og en
value ind i vores
HashMap. Vores
key i dette tilfælde er vores nøgleord vi skal lede efter i brugerens input. Det kunne være nøgleord som f.eks.
langsom,
bug,
installation og
crash. Vores value skal så være en passende response til vores nøgleord. Når du har løst opgaven, så sammenlign den med min.
- import java.util.HashSet;
- import java.util.ArrayList;
- import java.util.Random;
- import java.util.Iterator;
- import java.util.HashMap;
- /**
- * Klassen Responder - Denne klasse har til formål at autogenerere nogle svar, som sendes
- * til brugeren i henhold til hans spørgsmål, som kom via et input.
- * Inputtet er præsenteret for Responder klassen, som en kollektion af ord (words), som
- * vi så kan gå igennem for at finde nogle nøgleord. Hvis et nøgleord findes, vil vi kunne
- * generere et automatisk svar til det givne nøgleord, så bruegren for et så godt svar som muligt.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class Responder {
-
- private ArrayList<String> defaultResponses;
- private HashMap<String, String> responseMap;
- private Random randomGenerator;
-
- /**
- * Konstruktør for objekter af klassen Responder.
- */
- public Responder()
- {
- defaultResponses = new ArrayList<String>();
- responseMap = new HashMap<String, String>();
- randomGenerator = new Random();
- }
-
- /**
- * Denne metode udfylder vores ArrayList med nogle defaultResponses.
- */
- private void fillDefaultResponses()
- {
- defaultResponses.add("Det lyder underligt, kan du beskrive problemet yderligere?");
- defaultResponses.add("Det lyder interessant, fortael mig venligst mere.");
- defaultResponses.add("Din losning på problemet, er forklaret i manualen.");
- defaultResponses.add("Jeg forstår dig ikke helt, kunne du eventuelt uddybe problemet mere?");
- }
-
- /**
- * Denne metode udfylder vores HashMap med nogle responses til de specifikke nøgleord (keys).
- */
- private void fillResponseMap()
- {
- responseMap.put("langsom", "Hvis din computer er langsom, skal du investere i noget bedre hardware.");
- responseMap.put("bug", "Denne bug er os kendt, og vi gør alt hvad vi kan for at løse problemet.");
- responseMap.put("installation", "Hvis du har problemer med installationen, skal du læse kapitel 1 i manualen.");
- responseMap.put("crash", "Et crash kan betyde at du har gang i for meget med din PC. Luk programmer ned, som du ikke bruger.");
- }
-
- }
Nu har vi udfyldt de svar, som skal gives hvis vi møder et af vores nøgleord i brugerens input. Nu skal vi så lave en lille metode, som udskriver et vilkårligt svar fra vores
ArrayList.
Udfordrings Opgave - Lav en accessor metode, som er private og hedder getDefaultResponse(). Return typen til denne metode skal være
String. Lav nu en lokal variabel med datatypen
int, og initialiser den med din
randomGenerator til at genere et tal imellem 0 og størrelsen på vores
ArrayList (brug metoden
nextInt() fra
Random klassen, og brug så
ArrayList'ens metode
size() som parameter til denne metode). Vores statement til den lokale variabel skal så se således ud -
int index = randomGenerator.nextInt(defaultResponses.size()); - og returner så det objekt med det vilkårligt generede indeks i vores
ArrayList, med metoden
get(). Vores kode ser nu således ud.
- public class Responder {
-
- private ArrayList<String> defaultResponses;
- private HashMap<String, String> responseMap;
- private Random randomGenerator;
-
- /**
- * Konstruktør for objekter af klassen Responder.
- */
- public Responder()
- {
- defaultResponses = new ArrayList<String>();
- responseMap = new HashMap<String, String>();
- randomGenerator = new Random();
- }
-
- /**
- * Denne metode udfylder vores ArrayList med nogle defaultResponses.
- */
- private void fillDefaultResponses()
- {
- defaultResponses.add("Det lyder underligt, kan du beskrive problemet yderligere?");
- defaultResponses.add("Det lyder interessant, fortael mig venligst mere.");
- defaultResponses.add("Din losning på problemet, er forklaret i manualen.");
- defaultResponses.add("Jeg forstår dig ikke helt, kunne du eventuelt uddybe problemet mere?");
- }
-
- /**
- * Denne metode udfylder vores HashMap med nogle responses til de specifikke nøgleord (keys).
- */
- private void fillResponseMap()
- {
- responseMap.put("langsom", "Hvis din computer er langsom, skal du investere i noget bedre hardware.");
- responseMap.put("bug", "Denne bug er os kendt, og vi gør alt hvad vi kan for at løse problemet.");
- responseMap.put("installation", "Hvis du har problemer med installationen, skal du læse kapitel 1 i manualen.");
- responseMap.put("crash", "Et crash kan betyde at du har gang i for meget med din PC. Luk programmer ned, som du ikke bruger.");
- }
-
- /**
- * @return En String, med vores vilkårligt valgte defaultResponse.
- */
- private String getDefaultResponse()
- {
- //Generer et vilkårligt tal (indeks) mellem 0 og ArrayListens størrelse.
- int indeks = randomGenerator.nextInt(defaultResponses.size());
-
- //Returner så objektet på det nyligt generede indeks.
- return defaultResponses.get(indeks);
- }
-
- }
Nu skal vi til den sidste og mest betydningsfulde metode i denne klasse. Det er også den metode, som er mest vanskelig at lave, men vi skal nok komme igennem det.
Udfordrings Opgave - Lav en ny accessor metode, som er public. Kald metoden for generateResponses() og dens return type skal være String. Metoden skal bruge en parameter, nemlig parameteren -
HashSet<String> words - Som var vores
HashSet vi lavede i
InputReader klassen. Skriv ikke noget i metodens krop endnu, og vores kode ser nu således ud.
- import java.util.HashSet;
- import java.util.ArrayList;
- import java.util.Random;
- import java.util.Iterator;
- import java.util.HashMap;
- /**
- * Klassen Responder - Denne klasse har til formål at autogenerere nogle svar, som sendes
- * til brugeren i henhold til hans spørgsmål, som kom via et input.
- * Inputtet er præsenteret for Responder klassen, som en kollektion af ord (words), som
- * vi så kan gå igennem for at finde nogle nøgleord. Hvis et nøgleord findes, vil vi kunne
- * generere et automatisk svar til det givne nøgleord, så bruegren for et så godt svar som muligt.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class Responder {
-
- private ArrayList<String> defaultResponses;
- private HashMap<String, String> responseMap;
- private Random randomGenerator;
-
- /**
- * Konstruktør for objekter af klassen Responder.
- */
- public Responder()
- {
- defaultResponses = new ArrayList<String>();
- responseMap = new HashMap<String, String>();
- randomGenerator = new Random();
- }
-
- /**
- * Denne metode udfylder vores ArrayList med nogle defaultResponses.
- */
- private void fillDefaultResponses()
- {
- defaultResponses.add("Det lyder underligt, kan du beskrive problemet yderligere?");
- defaultResponses.add("Det lyder interessant, fortael mig venligst mere.");
- defaultResponses.add("Din losning på problemet, er forklaret i manualen.");
- defaultResponses.add("Jeg forstår dig ikke helt, kunne du eventuelt uddybe problemet mere?");
- }
-
- /**
- * Denne metode udfylder vores HashMap med nogle responses til de specifikke nøgleord (keys).
- */
- private void fillResponseMap()
- {
- responseMap.put("langsom", "Hvis din computer er langsom, skal du investere i noget bedre hardware.");
- responseMap.put("bug", "Denne bug er os kendt, og vi gør alt hvad vi kan for at løse problemet.");
- responseMap.put("installation", "Hvis du har problemer med installationen, skal du læse kapitel 1 i manualen.");
- responseMap.put("crash", "Et crash kan betyde at du har gang i for meget med din PC. Luk programmer ned, som du ikke bruger.");
- }
-
- /**
- * @return En String, med vores vilkårligt valgte defaultResponse.
- */
- private String getDefaultResponse()
- {
- //Generer et vilkårligt tal (indeks) mellem 0 og ArrayListens størrelse.
- int indeks = randomGenerator.nextInt(defaultResponses.size());
-
- //Returner så objektet på det nyligt generede indeks.
- return defaultResponses.get(indeks);
- }
-
- /**
- * @return En String med enten vores defaultResponse, eller vores value ud fra nøgleordet.
- */
- public String generateResponse(HashSet<String> words)
- {
-
- }
-
- }
Vi skal nu i vores metode have tilført en Iterator til vores kollektion. Iteratoren gør det nemmere for os at få adgang til hvert enkelt objekt i vores kollektion, for derefter at kunne bruge objektet inden vi gennemsøger videre i kollektionen. Vores []HashSet klasse har en metode, som hedder
iterator. Metoden henter en Iterator til denne kollektion, og vi kan herefter gemme det i en lokal variabel med datatypen
Iterator<String>. Vores metode ser nu således ud.
- /**
- * @return En String med enten vores defaultResponse, eller vores value ud fra nøgleordet.
- */
- public String generateResponse(HashSet<String> words)
- {
- //Vi kalder metoden iterator() fra vores HashSet kollektion, som vi fik i parameteren. Vi initialisere det herefter til en lokal variabel.
- Iterator<String> iter = words.iterator();
- }
Når vi har valgt at bruge en
Iterator med denne kollektion, så kan vi herefter bruge
Iterator's metoder. Vi skal jo gennemsøge kollektionen for nøgleord som er gemt i vores
HashMap. Til dette formål kan vi benytte en while løkke. Vi behøver ikke at initialisere en lokal variabel til denne løkke, da løkken skal køre indtil vores
boolean værdi returnerer falskt. I vores
Iterator, var der en metode som hed
hasNext(). Denne metode returnerede sandt så længe der var flere objekter i vores kollektion. Så snart den var nået igennem alle objekterne ville den returnere falskt, og derfor afslutter løkken sig selv. Så vi bruger denne metode som løkkens betingelse, og behøver derfor heller ikke noget tællerskridt.
Mini Opgave - Lav en while løkke, som bruger vores
Iterator metode,
hasNext() som betingelse. lad løkkens krop være tom for nu.
- /**
- * @return En String med enten vores defaultResponse, eller vores value ud fra nøgleordet.
- */
- public String generateResponse(HashSet<String> words)
- {
- //Vi kalder metoden iterator() fra vores HashSet kollektion, som vi fik i parameteren. Vi initialisere det herefter til en lokal variabel.
- Iterator<String> iter = words.iterator();
-
- //Kør løkken indtil vi har været igennem alle objekterne i hele kollektionen.
- while (iter.hasNext())
- {
-
- }
- }
Løkkens mangler nu noget kode i sin krop. Det som vi gerne vil have løkken til er at tage objektet ud af kollektionen for en stund og gemme det i en lokal variabel. Herefter skal vi tjekke om ordet i vores kollektion matcher en af vores
keys i vores
HashMap. Herefter gemmer vi det resultat i en anden lokal variabel. Nu tænker du måske, hvad skal vi dog gemme hvis ikke ordene matcher en af vores
keys. Til dette kan jeg svare at Java automatisk gemmer værdien
null, da et
HashMap også kan returnere
null værdier, hvis ikke der bliver fundet den rigtige
key. Ordet
null betyder simpelthen bare intet objekt/ingenting. Så hvis ordet
null forekommer, så er der altså ikke noget objekt i vores resultat. Dette er smart, da vi så nemt kan tjekke om den fandt noget eller ej.
Opgave I løkkens krop lav en lokal variabel med datatypen
String, og benyt så
Iterator'ens metode
next() til at hente det næste objekt i kollektionen. Herefter laver du endnu en lokal varaibel, også med datatypen
String, hvor du bruger metoden
get() fra
HashMap klassen. I metoden
get()'s parameter, skal du skrive navnet på den første lokale variabel du lavede i løkken. Din kode skulle nu gerne se således ud.
- /**
- * @return En String med enten vores defaultResponse, eller vores value ud fra nøgleordet.
- */
- public String generateResponse(HashSet<String> words)
- {
- //Vi kalder metoden iterator() fra vores HashSet kollektion, som vi fik i parameteren. Vi initialisere det herefter til en lokal variabel.
- Iterator<String> iter = words.iterator();
-
- //Kør løkken indtil vi har været igennem alle objekterne i hele kollektionen.
- while (iter.hasNext())
- {
- //Hent det næste objekt og gem det i en lokal variabel.
- String word = iter.next();
- //Prøv og tjekke om vores ord var en key i vores HashMap.
- String response = responseMap.get(word);
- }
- }
Nu skal vi så tjekke om resultatet fra vores
HashMap var
null eller ej. Hvis resultatet ikke var
null, så betød det at der var et match, altså at et af ordene matchede vores
key. Til at lave dette tjek med skal vi benytte et if statement.
Opgave - I din løkke lav et if statement, som tjekker om resultatet i din lokale variabel (i mit eksempel variablen response), ikke indeholder værdien
null. Måden du tjekker om noget ikke er lig med noget andet, er ved at bruge operatoren
! (udråbstegn). Udråbstegnet betyder
not, så i if statementets betingelse, kan du skrive -
response != null - som betyder at den skal køre statementets indhold hvis indholdet i response ikke er lig med (not equal too)
null. Inde i if statementets krop skal du så lave en return statement, som returnerer indholdet af response. Vores kode ser nu således ud.
- /**
- * @return En String med enten vores defaultResponse, eller vores value ud fra nøgleordet.
- */
- public String generateResponse(HashSet<String> words)
- {
- //Vi kalder metoden iterator() fra vores HashSet kollektion, som vi fik i parameteren. Vi initialisere det herefter til en lokal variabel.
- Iterator<String> iter = words.iterator();
-
- //Kør løkken indtil vi har været igennem alle objekterne i hele kollektionen.
- while (iter.hasNext())
- {
- //Hent det næste objekt og gem det i en lokal variabel.
- String word = iter.next();
- //Prøv og tjekke om vores ord var en key i vores HashMap.
- String response = responseMap.get(word);
-
- //Kør statementet hvis reponse ikke indeholder null.
- if (response != null)
- {
- return response;
- }
- }
- }
Nu er vores løkke færdig men vi er ikke helt færdige med metoden, fordi hvad nu hvis metoden hele tiden returnerede værdien
null, så ville den jo aldrig køre if statementet. Det er det vi skal rode bod på nu. lav nu uden for din løkke, altså efter løkken en return statement, som returnerer indholdet fra metoden getDefaultResponse(), som vi lavede tidligere. Vores metode ser nu således ud.
- /**
- * @return En String med enten vores defaultResponse, eller vores value ud fra nøgleordet.
- */
- public String generateResponse(HashSet<String> words)
- {
- //Vi kalder metoden iterator() fra vores HashSet kollektion, som vi fik i parameteren. Vi initialisere det herefter til en lokal variabel.
- Iterator<String> iter = words.iterator();
-
- //Kør løkken indtil vi har været igennem alle objekterne i hele kollektionen.
- while (iter.hasNext())
- {
- //Hent det næste objekt og gem det i en lokal variabel.
- String word = iter.next();
- //Prøv og tjekke om vores ord var en key i vores HashMap.
- String response = responseMap.get(word);
-
- //Kør statementet hvis reponse ikke indeholder null.
- if (response != null)
- {
- return response;
- }
- }
-
- //Hvis løkken ikke fandt et match og kun returnerede null værdier, så returner dette istedet.
- return getDefaultResponse();
- }
hele klassen
Responder ser nu således ud.
- import java.util.HashSet;
- import java.util.ArrayList;
- import java.util.Random;
- import java.util.Iterator;
- import java.util.HashMap;
- /**
- * Klassen Responder - Denne klasse har til formål at autogenerere nogle svar, som sendes
- * til brugeren i henhold til hans spørgsmål, som kom via et input.
- * Inputtet er præsenteret for Responder klassen, som en kollektion af ord (words), som
- * vi så kan gå igennem for at finde nogle nøgleord. Hvis et nøgleord findes, vil vi kunne
- * generere et automatisk svar til det givne nøgleord, så bruegren for et så godt svar som muligt.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class Responder {
-
- private ArrayList<String> defaultResponses;
- private HashMap<String, String> responseMap;
- private Random randomGenerator;
-
- /**
- * Konstruktør for objekter af klassen Responder.
- */
- public Responder()
- {
- defaultResponses = new ArrayList<String>();
- responseMap = new HashMap<String, String>();
- randomGenerator = new Random();
- }
-
- /**
- * Denne metode udfylder vores ArrayList med nogle defaultResponses.
- */
- private void fillDefaultResponses()
- {
- defaultResponses.add("Det lyder underligt, kan du beskrive problemet yderligere?");
- defaultResponses.add("Det lyder interessant, fortael mig venligst mere.");
- defaultResponses.add("Din losning på problemet, er forklaret i manualen.");
- defaultResponses.add("Jeg forstår dig ikke helt, kunne du eventuelt uddybe problemet mere?");
- }
-
- /**
- * Denne metode udfylder vores HashMap med nogle responses til de specifikke nøgleord (keys).
- */
- private void fillResponseMap()
- {
- responseMap.put("langsom", "Hvis din computer er langsom, skal du investere i noget bedre hardware.");
- responseMap.put("bug", "Denne bug er os kendt, og vi gør alt hvad vi kan for at løse problemet.");
- responseMap.put("installation", "Hvis du har problemer med installationen, skal du læse kapitel 1 i manualen.");
- responseMap.put("crash", "Et crash kan betyde at du har gang i for meget med din PC. Luk programmer ned, som du ikke
-
- bruger.");
- }
-
- /**
- * @return En String, med vores vilkårligt valgte defaultResponse.
- */
- private String getDefaultResponse()
- {
- //Generer et vilkårligt tal (indeks) mellem 0 og ArrayListens størrelse.
- int indeks = randomGenerator.nextInt(defaultResponses.size());
-
- //Returner så objektet på det nyligt generede indeks.
- return defaultResponses.get(indeks);
- }
-
- /**
- * @return En String med enten vores defaultResponse, eller vores value ud fra nøgleordet.
- */
- public String generateResponse(HashSet<String> words)
- {
- //Vi kalder metoden iterator() fra vores HashSet kollektion, som vi fik i parameteren. Vi initialisere det herefter
-
- til en lokal variabel.
- Iterator<String> iter = words.iterator();
-
- //Kør løkken indtil vi har været igennem alle objekterne i hele kollektionen.
- while (iter.hasNext())
- {
- //Hent det næste objekt og gem det i en lokal variabel.
- String word = iter.next();
- //Prøv og tjekke om vores ord var en key i vores HashMap.
- String response = responseMap.get(word);
-
- //Kør statementet hvis response ikke indeholder null.
- if (response != null)
- {
- return response;
- }
- }
-
- //Hvis løkken ikke fandt et match og kun returnerede null værdier, så returner dette istedet.
- return getDefaultResponse();
- }
-
- }
TechSupportSystem
Nu skal vi til vores sidste klasse, nemlig
TechSupportSystem. Så lav en klasse med dette navn, og gem den sammen med dine andre filer. husk at lave en konstruktør klar, så vi kan bruge den til at initialisere felter med.
Formålet med denne metode er at kontrollere de to klasser vi lige har lavet, og bruge dem sammen. Vi skal derfor deklarere to felter, som kan indeholde henholdsvis et objekt af typen
InputReader og
Responder. husk at initialisere dem med et objekt i konstruktøren, vores klasse ser nu således ud.
- /**
- * Klassen TechSupportSystem - Formålet med denne klasse er at bruge den som en slags
- * controller for henholdsvis InputReader og Responder.
- * Denne klasse har en metode som hedder start(), og kører indtil programmet lukkes ned med
- * en kommando.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class TechSupportSystem {
-
- private InputReader reader;
- private Responder responder;
-
- /**
- * Konstruktør for objekter af klassen TechSupportSystem.
- */
- public TechSupportSystem()
- {
- reader = new InputReader();
- responder = new Responder();
- }
-
- }
Lad os nu gøre de metoder vi skal lave klar. Det vil sige at vi skriver metodernes signatur i klassen, uden at skrive noget i kroppen. Vi skal bruge tre metoder. Den første skal hedder start(), og den skal være en mutator metode, som har en access modifier der er public. Herefter skal vi have to metoder, som hedder henholdsvis printWelcome() og printGoodbye(). De skal også være mutator metoder, men have en access modifier som er private. Lige som den sidste ting inden vi kigger på vores kode igen, skal du importere klassen
HashSet i starten. vores kode ser nu således ud.
- import java.util.HashSet;
- /**
- * Klassen TechSupportSystem - Formålet med denne klasse er at bruge den som en slags
- * controller for henholdsvis InputReader og Responder.
- * Denne klasse har en metode som hedder start(), og kører indtil programmet lukkes ned med
- * en kommando.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class TechSupportSystem {
-
- private InputReader reader;
- private Responder responder;
-
- /**
- * Konstruktør for objekter af klassen TechSupportSystem.
- */
- public TechSupportSystem()
- {
- reader = new InputReader();
- responder = new Responder();
- }
-
- /**
- * Denne metode starter hele vores Tech Support System, og kører indtil programmet for en afslutnings kommando.
- */
- public void start()
- {
-
- }
-
- /**
- * Udskriv en besked, der siger velkommen til Tech Support System.
- */
- private void printWelcome()
- {
-
- }
-
- /**
- * udskriv en besked, der siger farvel til Tech Support System.
- */
- private void printGoodbye()
- {
-
- }
-
- }
Lad os starte med at lave de to nederste metoder, da de er ret så simple. Metoden
printWelcome(), skal bare udskrive en velkomst besked som køres hver gang programmet startes. Find selv på en Sjov besked. Den anden metode
printGoodbye(), skal bare printe en afslutnings besked, som køres når programmet lukkes. Find også her selv på en sjov og passende besked. Programmet ser nu således ud.
- import java.util.HashSet;
- /**
- * Klassen TechSupportSystem - Formålet med denne klasse er at bruge den som en slags
- * controller for henholdsvis InputReader og Responder.
- * Denne klasse har en metode som hedder start(), og kører indtil programmet lukkes ned med
- * en kommando.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class TechSupportSystem {
-
- private InputReader reader;
- private Responder responder;
-
- /**
- * Konstruktør for objekter af klassen TechSupportSystem.
- */
- public TechSupportSystem()
- {
- reader = new InputReader();
- responder = new Responder();
- }
-
- /**
- * Denne metode starter hele vores Tech Support System, og kører indtil programmet for en afslutnings kommando.
- */
- public void start()
- {
-
- }
-
- /**
- * Udskriv en besked, der siger velkommen til Tech Support System.
- */
- private void printWelcome()
- {
- System.out.println("Velkommen til Tech Support System.");
- System.out.println("Du er velkommen til at skrive dit sporgsmaal, og jeg vil svare efter bedste evne.");
- System.out.println(); //Tom linje.
- System.out.println("For at afslutte programmet, skal du skrive kommandoen Afslut.");
- System.out.println(); //Tom linje.
- }
-
- /**
- * udskriv en besked, der siger farvel til Tech Support System.
- */
- private void printGoodbye()
- {
- System.out.println("Det var en god snak vi fik! Farvel...");
- }
-
- }
Nu skal vi så i gang med metoden
start(). Metoden skal køre en løkke, der køre så længe programmet er aktivt (indtil vi har skrevet en afslutningskommando). Derfor skal vi deklarere en lokal variabel, som har datatypen
boolean. Så vi skal altså gøre.
Udfordrings Opgave - I starten af metoden lav en lokal variabel med datatypen
boolean og kald variablen for finished. initialiser variablen med værdien false. Lav så et internt metode kald til metoden
printWelcome(). Herefter laver du en while løkke, som har betingelsen
!finished (not finished), så løkken køre indtil værdien i finished ændres til true. lad løkkens krop være tom. Efter løkken laver du så et internt metode kald til metoden
printGoodbye(). Din kode ser nu således ud.
- import java.util.HashSet;
- /**
- * Klassen TechSupportSystem - Formålet med denne klasse er at bruge den som en slags
- * controller for henholdsvis InputReader og Responder.
- * Denne klasse har en metode som hedder start(), og kører indtil programmet lukkes ned med
- * en kommando.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class TechSupportSystem {
-
- private InputReader reader;
- private Responder responder;
-
- /**
- * Konstruktør for objekter af klassen TechSupportSystem.
- */
- public TechSupportSystem()
- {
- reader = new InputReader();
- responder = new Responder();
- }
-
- /**
- * Denne metode starter hele vores Tech Support System, og kører indtil programmet for en afslutnings kommando.
- */
- public void start()
- {
- //En lokal variabel med værdien false.
- boolean finished = false;
-
- //Print velkomstbeskeden.
- printWelcome();
-
- //Kør løkken så længe at finished ikke er sandt (finished is not true = !finished).
- while (!finished)
- {
-
- }
-
- //Print farvelbeskeden.
- printGoodbye();
- }
-
- /**
- * Udskriv en besked, der siger velkommen til Tech Support System.
- */
- private void printWelcome()
- {
- System.out.println("Velkommen til Tech Support System.");
- System.out.println("Du er velkommen til at skrive dit sporgsmaal, og jeg vil svare efter bedste evne.");
- System.out.println(); //Tom linje.
- System.out.println("For at afslutte programmet, skal du skrive kommandoen Afslut.");
- System.out.println(); //Tom linje.
- }
-
- /**
- * udskriv en besked, der siger farvel til Tech Support System.
- */
- private void printGoodbye()
- {
- System.out.println("Det var en god snak vi fik! Farvel...");
- }
-
- }
Vi skal nu lave lidt kode i løkken. Koden i løkken, er noget, som køres hele tiden, indtil vi for vores afslutningskommando. Det er derfor her vi skal lave tjekket for om vores afslutningskommando har været der. Hvis du har læst min
printWelcome() besked, vil du se at vores afslutningskommando er
afslut. Det vil sige at vi skal bruge en if statement i vores løkke til at tjekke om brugerens input indeholdt ordet
afslut. For at tjekke om brugerens input indeholder et bestemt ord, findes en speciel metode i
String klassen, som hedder
contains(). Metoden returnerer sandt eller falskt hvis ordet er der eller ej. Men for at finde order, skal vi lige have fat i vores input fra brugere, så vi laver en lokal variabel, der henter metoden
getInput fra klassen
InputReader. Hvis vi husker tilbage, kan vi huske at denne metode havde en return type som var
HashSet<String>, hvilket betyder at datatypen for vores lokale variabel, skal være en
HashSet<String>. Men nu tilbage til vores if statement. Vi bruger altså metoden
contains() til vores lokale variabel, som indeholder objekter af
String's, og tjekker med
contains() metodens parameter om et af ordene fra vores
HashSet kollektion er ordet
afslut. Vores kode ser nu således ud.
- import java.util.HashSet;
- /**
- * Klassen TechSupportSystem - Formålet med denne klasse er at bruge den som en slags
- * controller for henholdsvis InputReader og Responder.
- * Denne klasse har en metode som hedder start(), og kører indtil programmet lukkes ned med
- * en kommando.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class TechSupportSystem {
-
- private InputReader reader;
- private Responder responder;
-
- /**
- * Konstruktør for objekter af klassen TechSupportSystem.
- */
- public TechSupportSystem()
- {
- reader = new InputReader();
- responder = new Responder();
- }
-
- /**
- * Denne metode starter hele vores Tech Support System, og kører indtil programmet for en afslutnings kommando.
- */
- public void start()
- {
- //En lokal variabel med værdien false.
- boolean finished = false;
-
- //Print velkomstbeskeden.
- printWelcome();
-
- //Kør løkken så længe at finished ikke er sandt (finished is not true = !finished).
- while (!finished)
- {
- //Hent alle ordene fra HashSet'et i InputReader og læg dem over i endnu en HashSet kollektion i denne klasse.
- HashSet<String> input = reader.getInput();
-
- //Hvis ordet 'afslut' er blandt ordene i vores input fra brugeren, skal if statementet køres.
- if (input.contains("afslut"))
- {
-
- }
- }
-
- //Print farvelbeskeden.
- printGoodbye();
- }
-
- /**
- * Udskriv en besked, der siger velkommen til Tech Support System.
- */
- private void printWelcome()
- {
- System.out.println("Velkommen til Tech Support System.");
- System.out.println("Du er velkommen til at skrive dit sporgsmaal, og jeg vil svare efter bedste evne.");
- System.out.println(); //Tom linje.
- System.out.println("For at afslutte programmet, skal du skrive kommandoen Afslut.");
- System.out.println(); //Tom linje.
- }
-
- /**
- * udskriv en besked, der siger farvel til Tech Support System.
- */
- private void printGoodbye()
- {
- System.out.println("Det var en god snak vi fik! Farvel...");
- }
-
- }
Nu skal vi bare udfylde vores krop i if statementet. Formålet med if statementet var jo at tjekke om inputtet indeholdt ordet afslut, og hvis den gjorde dette, skal den køre koden i statementet. Kommandoen afslut skulle jo afslutte programmet, og herved vores løkke. så i if statementets krop initialisere vi bare vores
finished variabel til true. Men lige sker der kun noget i løkken hvis if statementet er sandt, så vi skal have lavet en else part til if statementet, som kører hver eneste gang løkken er falsk, altså hver eneste finished ikke er true, og hver eneste gang der ikke er et ord med kommandoen afslut. så du skriver efter if statementets krop else, og laver en ny krop. Den vil nu køre else parten, hver eneste gang if statementet ikke køres. Vores kode ser nu således ud.
- import java.util.HashSet;
- /**
- * Klassen TechSupportSystem - Formålet med denne klasse er at bruge den som en slags
- * controller for henholdsvis InputReader og Responder.
- * Denne klasse har en metode som hedder start(), og kører indtil programmet lukkes ned med
- * en kommando.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class TechSupportSystem {
-
- private InputReader reader;
- private Responder responder;
-
- /**
- * Konstruktør for objekter af klassen TechSupportSystem.
- */
- public TechSupportSystem()
- {
- reader = new InputReader();
- responder = new Responder();
- }
-
- /**
- * Denne metode starter hele vores Tech Support System, og kører indtil programmet for en afslutnings kommando.
- */
- public void start()
- {
- //En lokal variabel med værdien false.
- boolean finished = false;
-
- //Print velkomstbeskeden.
- printWelcome();
-
- //Kør løkken så længe at finished ikke er sandt (finished is not true = !finished).
- while (!finished)
- {
- //Hent alle ordene fra HashSet'et i InputReader og læg dem over i endnu en HashSet kollektion i denne klasse.
- HashSet<String> input = reader.getInput();
-
- //Hvis ordet 'afslut' er blandt ordene i vores input fra brugeren, skal if statementet køres.
- if (input.contains("afslut"))
- {
- finished = true;
- }
- else
- {
-
- }
- }
-
- //Print farvelbeskeden.
- printGoodbye();
- }
-
- /**
- * Udskriv en besked, der siger velkommen til Tech Support System.
- */
- private void printWelcome()
- {
- System.out.println("Velkommen til Tech Support System.");
- System.out.println("Du er velkommen til at skrive dit sporgsmaal, og jeg vil svare efter bedste evne.");
- System.out.println(); //Tom linje.
- System.out.println("For at afslutte programmet, skal du skrive kommandoen Afslut.");
- System.out.println(); //Tom linje.
- }
-
- /**
- * udskriv en besked, der siger farvel til Tech Support System.
- */
- private void printGoodbye()
- {
- System.out.println("Det var en god snak vi fik! Farvel...");
- }
-
- }
I vores else part skal vi generere et response ud fra brugerens input, som vi allerede har gemt i et
HashSet. Så vi laver i else delen en lokal variabel med datatypen
String, og kalder den f.eks. response. Herefter initialisere du variablen til at køre metoden fra Responder klassen, som hed
generateRespond(). Hvis du husker tilbage, skulle denne metode bruge en parameter, nemlig en kollektion af
String's i et
HashSet. Du vi allerede har en
HashSet kollektion med navnet input i vores metode, kan vi bare bruge dette som parameter. Herefter skal du udskrive variablen reponse's indhold. Vores kode ser nu således ud.
- import java.util.HashSet;
- /**
- * Klassen TechSupportSystem - Formålet med denne klasse er at bruge den som en slags
- * controller for henholdsvis InputReader og Responder.
- * Denne klasse har en metode som hedder start(), og kører indtil programmet lukkes ned med
- * en kommando.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class TechSupportSystem {
-
- private InputReader reader;
- private Responder responder;
-
- /**
- * Konstruktør for objekter af klassen TechSupportSystem.
- */
- public TechSupportSystem()
- {
- reader = new InputReader();
- responder = new Responder();
- }
-
- /**
- * Denne metode starter hele vores Tech Support System, og kører indtil programmet for en afslutnings kommando.
- */
- public void start()
- {
- //En lokal variabel med værdien false.
- boolean finished = false;
-
- //Print velkomstbeskeden.
- printWelcome();
-
- //Kør løkken så længe at finished ikke er sandt (finished is not true = !finished).
- while (!finished)
- {
- //Hent alle ordene fra HashSet'et i InputReader og læg dem over i endnu en HashSet kollektion i denne klasse.
- HashSet<String> input = reader.getInput();
-
- //Hvis ordet 'afslut' er blandt ordene i vores input fra brugeren, skal if statementet køres.
- if (input.contains("afslut"))
- {
- finished = true;
- }
- else
- {
- //Læg vores auto genererede response ind i en lokal variabel af typen String.
- String response = responder.generateResponse(input);
-
- //Udskriv vores autogenerede response.
- System.out.println(response);
- }
- }
-
- //Print farvelbeskeden.
- printGoodbye();
- }
-
- /**
- * Udskriv en besked, der siger velkommen til Tech Support System.
- */
- private void printWelcome()
- {
- System.out.println("Velkommen til Tech Support System.");
- System.out.println("Du er velkommen til at skrive dit sporgsmaal, og jeg vil svare efter bedste evne.");
- System.out.println(); //Tom linje.
- System.out.println("For at afslutte programmet, skal du skrive kommandoen Afslut.");
- System.out.println(); //Tom linje.
- }
-
- /**
- * udskriv en besked, der siger farvel til Tech Support System.
- */
- private void printGoodbye()
- {
- System.out.println("Det var en god snak vi fik! Farvel...");
- }
-
- }
Nu er vores system færdigt, og vi kan udarbejde en main klasse, med en main metode, som laver et objekt af
TechSupportSystem klassen, og kalder metoden
start() via dot notation. Vores Main klasse ser sådan her ud.
- /**
- * Klassen Main - Denne klasse indeholder main metoden,
- * som køres automatisk af Java. Vi kan derfor køre vores
- * program automatisk bare ved at køre hele Main filen.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class Main {
-
- /**
- * Dette er vores main metode.
- */
- public static void main(String[] args)
- {
- //Lav et objekt af TechSupportSystem klassen, og kør dens start() metode.
- TechSupportSystem supportSystem = new TechSupportSystem();
- supportSystem.start();
- }
-
- }
Vi ar midt i al vores kodning glemt noget, men det kan vi hurtigt rette. Vi skal i vores Responder klasse lave to kald til dens interne metoder i konstruktøren. Metoderne vi skal kalde er -
fillDefaultResponses() og
fillResponseMap - Grunden til dette er at vi jo skal have udfyldt vores kollektionerne med de auto genererede svar, ellers kan vi jo ikke få noget svar ud af dem. Vores Responder ser nu således ud.
- import java.util.HashSet;
- import java.util.ArrayList;
- import java.util.Random;
- import java.util.Iterator;
- import java.util.HashMap;
- /**
- * Klassen Responder - Denne klasse har til formål at autogenerere nogle svar, som sendes
- * til brugeren i henhold til hans spørgsmål, som kom via et input.
- * Inputtet er præsenteret for Responder klassen, som en kollektion af ord (words), som
- * vi så kan gå igennem for at finde nogle nøgleord. Hvis et nøgleord findes, vil vi kunne
- * generere et automatisk svar til det givne nøgleord, så bruegren for et så godt svar som muligt.
- *
- * @author Martin Rohwedder
- * @version 1.0
- */
- public class Responder {
-
- private ArrayList<String> defaultResponses;
- private HashMap<String, String> responseMap;
- private Random randomGenerator;
-
- /**
- * Konstruktør for objekter af klassen Responder.
- */
- public Responder()
- {
- defaultResponses = new ArrayList<String>();
- responseMap = new HashMap<String, String>();
- randomGenerator = new Random();
-
- fillDefaultResponses();
- fillResponseMap();
- }
-
- /**
- * Denne metode udfylder vores ArrayList med nogle defaultResponses.
- */
- private void fillDefaultResponses()
- {
- defaultResponses.add("Det lyder underligt, kan du beskrive problemet yderligere?");
- defaultResponses.add("Det lyder interessant, fortael mig venligst mere.");
- defaultResponses.add("Din losning på problemet, er forklaret i manualen.");
- defaultResponses.add("Jeg forstår dig ikke helt, kunne du eventuelt uddybe problemet mere?");
- }
-
- /**
- * Denne metode udfylder vores HashMap med nogle responses til de specifikke nøgleord (keys).
- */
- private void fillResponseMap()
- {
- responseMap.put("langsom", "Hvis din computer er langsom, skal du investere i noget bedre hardware.");
- responseMap.put("bug", "Denne bug er os kendt, og vi gør alt hvad vi kan for at løse problemet.");
- responseMap.put("installation", "Hvis du har problemer med installationen, skal du læse kapitel 1 i manualen.");
- responseMap.put("crash", "Et crash kan betyde at du har gang i for meget med din PC. Luk programmer ned, som du ikke
-
- bruger.");
- }
-
- /**
- * @return En String, med vores vilkårligt valgte defaultResponse.
- */
- private String getDefaultResponse()
- {
- //Generer et vilkårligt tal (indeks) mellem 0 og ArrayListens størrelse.
- int indeks = randomGenerator.nextInt(defaultResponses.size());
-
- //Returner så objektet på det nyligt generede indeks.
- return defaultResponses.get(indeks);
- }
-
- /**
- * @return En String med enten vores defaultResponse, eller vores value ud fra nøgleordet.
- */
- public String generateResponse(HashSet<String> words)
- {
- //Vi kalder metoden iterator() fra vores HashSet kollektion, som vi fik i parameteren. Vi initialisere det herefter
-
- til en lokal variabel.
- Iterator<String> iter = words.iterator();
-
- //Kør løkken indtil vi har været igennem alle objekterne i hele kollektionen.
- while (iter.hasNext())
- {
- //Hent det næste objekt og gem det i en lokal variabel.
- String word = iter.next();
- //Prøv og tjekke om vores ord var en key i vores HashMap.
- String response = responseMap.get(word);
-
- //Kør statementet hvis reponse ikke indeholder null.
- if (response != null)
- {
- return response;
- }
- }
-
- //Hvis løkken ikke fandt et match og kun returnerede null værdier, så returner dette istedet.
- return getDefaultResponse();
- }
-
- }
Færdig
Nu er vores Tech Support System færdigt, og du kan nu kompilerer dine Java filer, og herefter køre Main klassen. Dit output kunne nu se således ud, men det er ikke helt sikkert, da det også afhænger af brugerens input. prøv engang at skrive noget input, og brug gerne nogle af de ord som vi lavede i vores
HashMap's
key -
langsom,
bug,
installation og
crash - men prøv også sætninger uden disse ord for at få et vilkårligt genereret defaultResponse. Prøv dig frem, og skriv så afslut, for at afslutte programmet.

Nu blev programmeringen en tant mere interessant, da vi kan bruge programmet, med nogle input fra en bruger, uden at vi kender indholdet. Vi kunne simpelthen læse/scanne indholdet ved hjælp af vores Scanner klasse, og gemme indholdet i en HashSet kollektion. Vi har også lært om Hvad fordelene ved et HashMap var, nemlig at man kunne gemme 2 objekter i stedet for 1, også bruge det ene objekt som en key, til at få adgang til det andet objekt. Vi har set på hvordan man kan bruge en Iterator til at gennemgå objekterne i en kollektion en for en, meget nemmere. Alt i alt, har vi lært en hel masse, faktisk forholdsvis sværere teori end man lige skulle tro, og jeg håber at du vil følge med i den 6. del af denne Java artikel kavalkade.
Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.
Del også gerne artiklen med dine Facebook venner:
Kommentarer (7)
Hej! Forstår ikke den del med for'each-løkken. Hvordan ender elementerne i wordArray i HashSet-kollektionen words? words er jo tom fra starten af. " words.add(word); " tilføjer den ikke bare elementer fra wordArray TIL word? Kan jeg få det forklaret på en lidt mere idiotvenlig måde?

PS. Er endnu ikke begyndt med klassen "Responder", men tænkte at jeg først lige ville være sikker på "inputReader" klassen, før jeg begyndte på den næste klasse.
Vi har et almindeligt String Array med navnet wordArray
- String[] wordArray = input.splitLine(" ");
Her tager vi så linjen skrevet af brugeren, og splitter denne hver eneste gang der er et mellemrum. Vi har nu fyldt vores array op med ord (words). Det næste vi gør er at deklarere og initalisere (oprette) et objekt af klassen HashSet, som vi ligger ind i en lokal variabel kaldet words.
- HashSet<String> words = new HashSet<String>();
Nu har vi to forskellige kollektioner, og vi kan nu benytte en løkke, til at tage ordene fra den ene kollektion/array (wordArray), og lægge disse ind i vores anden kollektion (words (vores HashSet)). Jeg har i eksemplet valgt at bruge en for each løkke, da vi skulle se hvordan sådan en virkede.
Måden den virker på er at vi har en lokal variabel i løkkens hoved, samt den kollektion, som den skal køre igennem. F.eks. kunne den se således ud -
for (String element : kollektion) { } - Her har vi i løkkens hoved datatypen String samt ordet element. Ordet element er bare et valgfrit navn, da String element er en deklaration af en lokal variabel. Formålet med denne lokale variabel er at vi har et sted hvor hvert element bliver gemt fra vores kollektion. En for each løkke kører nemlig så længe at der er elementer tilbage i vores kollektion/array, og hver eneste gang den møder et nyt element, lægger den dette ind i vores lokale variabel element, som vi deklarerede i løkkens hoved. Efter kolonnet ( : ), har vi ordet kollektion. Dette er her du skal indsætte navnet på den kollektion, som vi skal gå igennem. Lad os se det eksempel der var i artiklen.
- for (String word : wordArray)
- {
- //Indsæt værdien fra den lokale variabel word, til vores HashSet kollektion.
- words.add( word );
- }
Som du kan se i vores eksempel, så har vi en lokal variabel med navnet word. Vi ønsker at kører igennem vores kollektion med navnet wordArray, hvilket betyder at så længe der er elementer tilbage i dette array, så vil løkken køre. Hvis wordArray nu indeholdt 10 ord, vil løkken altså køre ti gange. Det betyder at vores variabel word vil blive fyldt med et nyt element (ord) 10 gange. Inde i løkkens kode, kalder vi en metode, med navnet add(). Denne metode er at finde i HashSet klassen, og parameteren den kræver er den værdi, som den skal lægge ind i vores HashSet kollektion. linjen -
words.add( word ); - Tager altså værdien i vores lokale variabel word, og lægger denne ind i vores HashSet kollektion.
Hvis vi skulle lave det samme med en anden løkke, f.eks. en while løkke, så ville eksemplet se således ud
- String[] wordArray = inputLine.split(" ");
-
- HashSet<String> words = new HashSet<String>();
-
- //Tælle variabel til vores while løkke.
- int i = 0;
-
- //Kør løkken indtil at der ikke er flere elementer tilbage
- while ( i < wordArray.length )
- {
- //Dette er vores lokale variabel, som vi gemmer elementet i
- String word = wordArray[ i ];
-
- //Indsæt vores element i kollektionen words.
- words.add( word );
-
- //Tæl vores tælle variabel 1 op.
- i++;
- }
While løkken her laver også en lokal variabel, med navnet word, men denne variabel er bare deklareret i løkkens krop, og ikke i dens hoved. Håber at det hjalp lidt mere til forståelsen for hvordan for each løkken fungere, og hvordan vi får elementer fra wordArray over i vores HashSet kollektion 'words'.
Mange tak! Håber du en eller anden dag bliver Java'lærer på et universitet, for du er meget god til at forklare hvordan Java fungerer!
Så det der sker i for each løkken er:
Den erklærer en lokal variabel.
Den putter alle elementerne i en forudbestemt kollektion ind i den lokale variabel.
Og add() metoden fungere således:
words(Der hvor der skal add'eres noget TIL)
word(Det hvor der skal add'eres FRA)
Har jeg forstået det korrekt?
Ja næsten.. Den putter ikke alle elementerne ind i den loakel variabel på¨en gang, men gør det hver gang at løkken kører, altså 10 gange hvis ens kollektion indeholder 10 elementer.
add() metoden tilføjer bare et nyt element til vores HashSet kollektion.
Men den add'ere jo word IND i Words 10 gange, fordi løkken bliver løbet igennem 10 gange, vil det ikke betyde at der kommer 65 elementer ind i words? For, for hver gang løkken bliver løbet igennem, kommer der et element mere ind i word, som så bagefter på ny, bliver tilføjet til words?
Nej, Variablen word for et nyt element hver gang løkken kører.
Første gang løkken kører lægges det første element fra wordArray ind variablen word. Vi benytter nu metoden add(), til at tilføje værdien i variablen word til vores words kollektion (HashSet).
Næste gang løkken kører lægges det næste element ind i variablen word (den overskriver altså det gamle element). Metoden add() tilføjer nu elementet til vores words kollektion, så dan nu kommer til at indeholde to elementer. Sådan gør den indtil at wordArray er tom for elementer.
Hvis wordArray indeholder 10 elementer, f.eks. {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}, så vil vores løkke køre 10 gange (fordi wordArray indeholder 10 elementer), og vi tager nu hvert element og lægger ind i vores HashSet ved hjælp af metoden add().
Du skal være
logget ind for at skrive en kommentar.