TUTORIAL: KLASSER & OBJEKT I denna tutorial lär vi oss att använda klasser och objekt samt hur vi bygger en enkel applikation kring dessa. I tutorialen kommer det finnas en mängd kod som du antingen kan följa med i och även skriva av för att bygga din egen applikation. Arbetar du igenom denna tutorial så får du med dig alla de grunder som du behöver för att kunna bygga egna objektorienterade applikationer. Detta är en praktisk övning, det teoretiska delarna behöver du gå igenom först för att till fullo ta till dig denna övning. Tanken är att det skall komma ytterligare två tutorials för detta moment, den ena bygger en hel applikation till vår grundklass i konsollmiljö och den andra skall bygga en applikation i en grafisk miljö. Bägge dessa tutorials fokuserar på listor som ingår i detta moment. INNEHÅLLSFÖRTECKNING 1 Skapa klass... 1 1.1 UML... 1 1.2 Skapa applikationen CarDemo... 1 2 Skapa objekt... 2 3 Skapa funktion för utskrift... 3 3.1 UML... 4 4 Skapa konstruktorer... 5 4.1 UML... 7 5 get- och set-metoder... 8 5.1 UML... 9 6 Validera data... 10 6.1 UML... 12 7 Låt användaren mata in data... 13 8 Hela applikationens kod... 14 8.1 cardemo.java... 14 8.2 car.java... 15
Thoren Innovation School Programmering 1 Sid 1 1 SKAPA KLASS Vi börjar med att kolla på hur vår klass skall se ut, för att visa hur klasserna skall se ut använder vi oss av UML (Unified Modeling Language). All UML i denna tutorial har ritats upp i webbapplikationen http://draw.io/ 1.1 UML Klassmodellen i UML består av tre rader Ø den första raden innehåller klassens namn Ø den andra raden innehåller klassens medlemsvariabler. Den består av tre delar; o medlemsvariabelns synlighet (+) innebär public, (-) innebär private o medlemsvariabelns namn o medlemsvariabelns typ Ø den tredje raden innehåller klassens metoder, här beskrivs metodernas namn, argument och returvärde. Den är just nu tom, men vi kommer lägga till metoder senare. 1.2 SKAPA APPLIKATIONEN CARDEMO Vi skapar ett nytt konsollprojekt, vi döper det till CarDemo och vi kan låta NetBeans skapa mainklassen CarDemo.java. Vi väljer själva att skapa en fil till och döper den till Car.java, det är här som vi kommer att skapa klassen Car. I Car skall vi nu skapa den klass som vi skall använda, börja med att skriva in följande kod i Car.java. Denna kod går inte att köra just nu då vi inte har skrivit någon kod i klassen CarDemo som kör igång programmet. Du kan ändå testa att kompilera din applikation så att du ser att inga error finns.
Thoren Innovation School Programmering 1 Sid 2 2 SKAPA OBJEKT Det är dags att skriva kod i mainfunktionen i klassen CarDemo så att vi kan köra vårt program, i mainfunktionen skapar vi nu ett objekt c, av typen Car. Vi tilldelar också medlemsvariablerna för objektet c olika värden såsom regnr, bilmärke och modell. Att skapa ett objekt av en klass kallas att man skapar en instans av klassen. Tänk dig klassen som en mall där alla objekt utgår ifrån, klassen talar om vilka medlemsvariabler och medlemsmetoder som objektet skall innehålla men klassen styr inte vilka värden som skall lagras. Alla bilar lagrar samma typ av information men varje unik bil lagrar unik information om t.ex. regnr och årsmodell. För att skapa ett objekt så måste ett nytt objekt skapas (new Car()) och vi måste också skapa en variabel som pekar på detta objekt, denna variabel har vi här döpt till c1. Utskriften ser då ut så här.
Thoren Innovation School Programmering 1 Sid 3 3 SKAPA FUNKTION FÖR UTSKRIFT Eftersom tanken är att kunna skapa många bilar i vår applikation så skapar vi metoden tostring() i klassen Car som sedan kan anropas från varje objekt, detta är en medlemsmetod. tostring() är en metod som finns i alla objekt genom arv, men vi kan skapa en egen tostring()-metod som skriver ut informationen om ett objekt på det sätt som vi vill. Om vi skriver ut den ärvda tostring() så kommer det se ut så här. Koden skall läggas i CarDemo.java. Vi bygger nu metoden tostring() som inte har några inparametrar men returnerar en String. Här skulle man kunna välja att skriva ut texten inne i metoden men jag väljer att returnera resultatet och sedan skriva ut det inne i programmet när jag tycker det är lämpligt. På rad 11, finns det nu en glödlampa och väljer jag att låta NetBeans göra vad programmet föreslår så kommer det läggas till en text om @Override vilket innebär att vi tydliggör att denna metod skall lagras över den ordinarie metoden tostring() som alla klasser ärver. Välj att följa NetBeans förslag eller hoppa över det, din applikation kommer köras oavsett.
Thoren Innovation School Programmering 1 Sid 4 Tidigare provade vi att skriva ut c1.tostring() och då skrevs bara en referens ut till objektet. Nu när vi har skrivit om metoden så testar vi att skriva ut objektet en gång till. Det blev mycket bättre. Vill du förändra utskriften för en viss typ av objekt så är det metoden tostring() i klassen Car som skall förändras, på detta sätt garanterar vi att alla objekt av en viss typ alltid behandlas på samma sätt. 3.1 UML Nu har vi lagt till en metod i vår klass och det är dags att uppdatera vårt UML-diagram. Vi lägger till metoden i den nedersta raden och anger tre saker; Ø medlemsmetoden synlighet (+) innebär public, (-) innebär private Ø medlemsmetodens namn, inom parentes skrivs också eventuella inparameterar till metoden. Ø medlemsmetodens returtyp
Thoren Innovation School Programmering 1 Sid 5 4 SKAPA KONSTRUKTORER En konstruktor är en speciell typ av metod som har samma namn som klassen och som anropas när vi skapar en instans av klassen. En konstruktor saknar returvärde. Konstruktorn används för att initiera medlemsvariabler i klassen. Det går att skapa flera konstruktorer, där varje konstruktor skiljer sig med avseende på antal parametrar eller parametertyper. Om inga konstruktorer definieras kommer kompilatorn generera en konstruktor som inte tar några argument. Denna konstruktor kallas för en förvald konstruktor (default constructor, kallas därför också för defaultkonstruktor ibland). När du skapar en konstruktor så faller den förvalda konstruktorn som skapar ett tomt objekt. Därför måste vi, om vi fortfarande vill ha en sådan, skapa den själva. Lägg extra märke till this som hela tiden pekar på medlemsvariabeln i ett objekt. Genom att använda this så kan vi i detta läge använda samma variabelnamn men samtidigt hålla isär dem från vilken som tillhör objektet och vilken som är en inparameter i konstruktorn eller metoden. Att hålla nere antalet variabler, och ge dem beskrivande och vettiga namn, underlättar vårt arbete i större projekt. Vi skapa konstruktorerna i filen Car.java. Rad 16 och 17 kan slås ihop till en rad, jag har bara gjort en radbrytning här för att inte koden skall fortsätta utanför det röda strecket. Eftersom deafultkonstruktorn inte längre skapas automatiskt när vi skapar en egen så skapar vi en helt tom konstruktor. Hade vi inte haft den kvar hade vår gamla kod när vi skapar Car c1 inte längre fungerat. Nu testar vi att använda den nya konstruktorn, detta gör vi på rad 18 i filen CarDemo.java.
Thoren Innovation School Programmering 1 Sid 6 När vi kör vårt program ser utskriften ut så här; Om det inte ser ut exakt så för dig så beror det på att jag har flyttat de två radbrytningarna innan Bilinformation, \n\n till slutet av metoden tostring(), allt för att göra bättre utskrifter i denna tutorial. I kod ser det ut så här i Car.java;
Thoren Innovation School Programmering 1 Sid 7 4.1 UML Nu har vi lagt till två konstruktorer i vår klass och det är dags att uppdatera vårt UML-diagram. Vi lägger till konstruktorerna först i den delen där vi listar metoderna och anger tre saker; Ø konstruktorns synlighet är alltid public (+) Ø konstruktorns namn är alltid samma som klassen Ø eventuella inparametrar anges inom parentesen, inget returvärde kommer från en konstruktor
Thoren Innovation School Programmering 1 Sid 8 5 GET- OCH SET-METODER Synlighet för medlemsvariabler, och i viss mån medlemsmetoder, styr vi med nyckelorden public eller private. För att skydda innehållet i våra objekt så skall vi nu ändra medlemsvariablernas synlighet från public till private: Metoderna skall fortfarande vara publika. Eventuella metoder som inte kommer användas utanför objektet skulle man kunna låta vara privata, just nu har vi ingen sådan metod som bara använd inom objektet men det kanske kommer senare. Nu kan du inte längre köra programmet utan kommer få felmeddelande på de rader som kräver att medlemsvariablernas synlighet är public. Det beror på att objekten som är skapade i CarDemo inte längre får prata med medlemsvariablerna i objektet c1. För att komma runt detta måste vi nu skapa metoder för att läsa och skriva till objektets medlemsvariabler, vi skall skapa get- och setmetorer (getters and setters). Här visas koden för metoderna setregnr() och getregnr() som används för att ge regnr ett värde och även läsa av värdet i regnr. På detta sätt görs alla getters och setters. Viktigt att tänka på att year och forsale har andra datatyper och därför kommer deras getters och setters se lite annorlunda ut.
Thoren Innovation School Programmering 1 Sid 9 Getters och setters för year och forsale bör se ut så här när du är klar; Dags att ändra i programfilen. Programmet kan inte längre se medlemsvariablerna och därför måste vi använda våra set-metoder för att sätta värden till objektet. Nu försvinner felmeddelanden och vi kan åter köra vår applikation. 5.1 UML Vi uppdaterar vårt UML-diagram med de nya metoderna och den ändrade synligheten för våra medlemsvariabler.
Thoren Innovation School Programmering 1 Sid 10 6 VALIDERA DATA Om vi anger ett ologiskt värde till någon av våra medlemsvariabler så skapar vi oss problem. Vi tänker oss att man anger årsmodellen som 12 för en bil, hur skall du programmet reagera på detta? Ännu värre är om man anger ett ologiskt värde som 1450 eller -800. Detta borde vi ta hand om på något sätt. Vi har ju redan skapat en metod som heter setyear(), den kan vi bygga vidare på och lägga in lite logik i den. Är det bättre med -1 än -800 eller 1450? -1 är ett tal som vi kan tala om är felaktigt och ta om hand på annat sätt. Du som programmerare, eller beställaren, bestämmer vilka regler som skall gälla i applikationen. Det viktigaste är att veta hur man skall ta hand om felaktigt data. Vi vill meddela användaren att alla årtal som lagras som -1 är felaktig och därför måste vi skriva om vår kod. Vi har två möjligheter att göra detta; 1. Vi skriver om metoden tostring() så att applikationen kollar om year = -1, om det är sant så skriver vi ut något om felaktigt årtal. 2. Vi skriver om metoden getyear() så att den metoden levererar ett årtal som en String eller ett meddelande som en String. Eftersom vi vill ha en så logisk kod som möjligt väljer vi det andra alternativet. När vi nu har skapat fina get- och set-metoder så är det lika bra att anropa dessa från konstruktorn som tar argument. Defaultkonstruktorn låter vi vara, den kan få skapa objekt helt utan kontroll (här skulle vi kunna sätta kod i defaultkonstruktorn så att alla nya objekt skapas med förvalda värden). Vi ställer om konstruktorn så att den anropar våra setmetoder, det finns ju ingen anledning att skapa logik om vi inte använder den. Här kommer NetBeans att klaga på att vi använder en metod som är möjlig att ändra i en annan klass som senare skulle kunna ärva av Car. Hur detta fungerar och hur man kan lösa det på olika sätt återkommer vi till i nästa kurs programmering2. Du kan välja alternativet make the class Car final, vilket innebär att det inte går att skapa klasser som ärver av Car, det är ändå inget vi kommer syssla med under denna kurs.
Thoren Innovation School Programmering 1 Sid 11 På samma sätt som vi valt att använda logiken i våra setmetoder när vi matar in data behöver vi använda logiken i getmetoderna när vi skall skriva ut information om en bil. Den uppmärksamme ser att jag har tagit bort den separerade deklarationen på första raden och lagt deklarationen av s till samma rad där vi tilldelar den ett värde, att deklarera och tilldela samtidigt kallas att initiera en variabel. Det gör ingen större skillnad i prestanda men nu när våra filer börjar växa i storlek så blir det mer intressant att undvika onödig kod. Eftersom vi har bestämt oss för att göra om getyear() så att logiken hamnar inne i den metoden så bör vi göra samma med getforsale() så att det resulterar i en text istället för en booleanvariabel som vi ändå måste behandla senare. Vi fixar det direkt. Vi har inte tjänat speciellt mycket kod genom denna förändring men istället har vi fått en gemensam struktur genom hela applikationen. Om du tittar på de två metoderna ovan så ser du att jag inte deklarerar någon stringvariabel alls utan bygger istället upp strängar som jag direkt returnerar som resultat av metoden. Återigen ett sätt att jobba på som gör att man inte behöver skapa onödig kod eller onödiga variabler. Samtidigt så fungerar det tidigare sättet lika bra, det går bara att göra det på olika sätt.
Thoren Innovation School Programmering 1 Sid 12 Vi får inte glömma bort att testa det vi har gjort nu. Snyggt! 6.1 UML Dags att uppdatera UML-diagrammet med det nya returvärdet för funktionen getyear() och getforsale().
Thoren Innovation School Programmering 1 Sid 13 7 LÅT ANVÄNDAREN MATA IN DATA Än då länge är vår applikation inte så bra, all information om bilar som är inmatade är ju redan hårdkodade i programmet CarDemo. Nu skall vi testa att låta användaren skapa en egen bil. Alla variabler har deklarerats precis innan inläsningen. Det går lika bra att deklarera dem ihop med c1 först i programkoden. Glöm inte bort att importera Scannerpaketet! Det enda som kanske behöver en extra presentation är rad 38. I forsale, som är en variabel av typen boolean, händer följande; Programmet läser in hela inmatningen, kollar om den första bokstaven är ett stort J och om detta är sant så lagras true i variabeln forsale, annars lagras false. Så här bör programmet fungera nu både med inmatning och utskrift. Nu har vi en fungerande applikation som givetvis kan byggas ut ytterligare, att lagra objekten i enskilda objekt är kanske inte det smidigaste. I kommande tutorial skall vi bygga vidare på denna uppgift och lagra bilar i en lista.
Thoren Innovation School Programmering 1 Sid 14 8 HELA APPLIKATIONENS KOD Här kommer hela applikationens kod. Det som kan påpekas är att kommentarerna i koden är i tunnaste laget, framförallt skulle jag vilja att metoder, bortsett från enkla getters och setters borde kommenteras bättre. I vår applikation gäller detta getyear(), getforsale(), setyear() och tostring(). Här borde det kommenteras vad som sker i metoden, vilka eventuella inparametrar som krävs och vad som returneras. 8.1 CARDEMO.JAVA
Thoren Innovation School Programmering 1 Sid 15 8.2 CAR.JAVA
Thoren Innovation School Programmering 1 Sid 16