Kapittel 8: Programutvikling



Like dokumenter
Kapittel 9: Sortering og søking Kort versjon

Kapittel 7: Mer om arv

Jentetreff INF1000 Debugging i Java

Eksekveringsrekkefølgen (del 1) Oppgave 1. Eksekveringsrekkefølgen (del 2) Kommentar til oppgave 1. } // class Bolighus

Kapittel 1: Datamaskiner og programmeringsspråk

Kapittel 15: Grafiske brukergrensesnitt: Enkel GUI. Del I

programeksempel Et større En større problemstilling Plan for forelesingen Problemstillingen (en tekstfil) inneholdt ordet "TGA"

Eksamen. Objektorientert Programmering IGR 1372

Dagens tema Kapittel 8: Objekter og klasser

Fra Python til Java, del 2

Forkurs INF1010. Dag 1. Andreas Færøvig Olsen Tuva Kristine Thoresen

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister

Eksamen i emnet INF100 Grunnkurs i programmering (Programmering I) og i emnet INF100-F Objektorientert programmering i Java I Løsningsforslag

UNIVERSITETET I OSLO

INF1000 undervisningen INF 1000 høsten 2011 Uke september

UNIVERSITETET I OSLO

Forkurs INF1010. Dag 2. Andreas Færøvig Olsen Gard Inge Rosvold Institutt for Informatikk, 14.

INF1000 Metoder. Marit Nybakken 16. februar 2004

2 Om statiske variable/konstanter og statiske metoder.

Forklaring til programmet AbstraktKontoTest.java med tilhørende filer Konto.java, KredittKonto.java, SpareKonto.java

INF1000: Forelesning 7. Konstruktører Static

INF1010 våren januar. Objektorientering i Java

public static <returtype> navn_til_prosedyre(<parameter liste>) { // implementasjon av prosedyren

public static <returtype> navn_til_prosedyre(<parameter liste>) { // implementasjon av prosedyren

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister Videre

INF1000: Forelesning 7

INF1010 våren 2019 Onsdag 30. januar. Mer om unntak i Java (med litt repetisjon av I/O først)

Oversikt. INF1000 Uke 1 time 2. Repetisjon - Introduksjon. Repetisjon - Program

IN1010 våren januar. Objektorientering i Java

Introduksjon til objektorientert programmering

INF Notater. Veronika Heimsbakk 10. juni 2012

TOD063 Datastrukturer og algoritmer

INF1010, 22. mai Prøveeksamen (Eksamen 12. juni 2012) Stein Gjessing Inst. for Informatikk Universitetet i Oslo

Kapittel 1. Datamaskiner og programmeringsspråk. 1.1 Programmering

INF Uke 10. Ukesoppgaver oktober 2012

EKSAMEN 6108/6108N PROGRAMMERING I JAVA Alt trykt og skriftlig materiale.

Fra Python til Java. En introduksjon til programmeringsspråkenes verden. Dag Langmyhr

Repitisjonskurs. Arv, Subklasser og Grensesnitt

NB!!! Veldig korte svar er gitt her. Disse burde det vært skrevet mer på ved en eksamen..

Introduksjon til objektorientert. programmering. Hva skjedde ~1967? Lokale (og globale) helter. Grunnkurs i objektorientert.

Forelesning inf Java 5

Forelesning inf Java 5

TDT4100 Objektorientert programmering

Kapittel 13: Grafiske brukergrensesnitt INF 100. Java som første programmeringsspråk

i=0 Repetisjon: arrayer Forelesning inf Java 4 Repetisjon: nesting av løkker Repetisjon: nesting av løkker 0*0 0*2 0*3 0*1 0*4

Forelesning inf Java 4

INF1000 EKSTRATILBUD. Stoff fra uke 1-5 (6) 3. oktober 2012 Siri Moe Jensen

Rekursjon. (Big Java kapittel 13) Fra Urban dictionary: recursion see recursion. IN1010 uke 8 våren Dag Langmyhr

JSP - 2. Fra sist. Hvordan fungerer web? Tjenerside script HTML. Installasjon av Web-tjener Et enkelt JSP-script. Ønsker dynamiske nettsider:

Løsningsforslag Test 2

1- og 2-veis Innkapsling Java Stabel Kø Prio-kø Iterator. Enveis- og toveislister Innkapsling («boxing») (Big Java 6.8.5)

GUI («Graphical User Interface») del 2

1- og 2-veis Innkapsling Java Stabel Kø Prio-kø Iterator. Enveis- og toveislister Innkapsling («boxing») (Big Java 6.8.5)

UNIVERSITETET I OSLO

GUI («Graphical User Interface») del 2

Konstruktører. Bruk av konstruktører når vi opererer med "enkle" klasser er ganske ukomplisert. Når vi skriver. skjer følgende:

IN1010. Fra Python til Java. En introduksjon til programmeringsspråkenes verden Dag Langmyhr

INF Løsning på seminaropppgaver til uke 8

Løsningsforslag ukeoppg. 2: 31. aug - 6. sep (INF Høst 2011)

UNIVERSITETET I OSLO

Avdeling for ingeniørutdanning Institutt for teknologi

IN1010 V18, Obligatorisk oppgave 5

Rekursjon. (Big Java kapittel 13) Fra Urban dictionary: recursion see recursion. IN1010 uke 8 våren Dag Langmyhr

I dag skal vi se på. INF 1000 (uke 2) Variabler, tilordninger og uttrykk. Gruppene starter denne uken! Klart for første oblig

UNIVERSITETET I OSLO

Kapittel 6: Arv. Redigert av: Khalid Azim Mughal

Tre måter å lese fra terminal. Java 4. Eksempel. Formatert utskrift til skjerm

UNIVERSITETET I OSLO

Eksamen Objektorientert Programmering 2013

Litt mer om uttrykk: ++ og -- INF1000 : Forelesning 4. Oppgave. Blokker. 0 udefinert udefinert. Alternativ 2 Postfiks-operator

Oblig 4 (av 4) INF1000, høsten 2012 Værdata, leveres innen 9. nov. kl

Leksjon 4. Metoder. Program, klasse og metode

Kort om meg. INF1000 Uke 2. Oversikt. Repetisjon - Introduksjon

Hva er verdien til variabelen j etter at følgende kode er utført? int i, j; i = 5; j = 10; while ( i < j ) { i = i + 2; j = j - 1; }

Programmering Høst 2017

Algoritmer og datastrukturer Kapittel 3 - Delkapittel 3.1

6108 Programmering i Java. Leksjon 4. Metoder. Roy M. Istad 2015

UNIVERSITETET I OSLO

Dagens tema: 12 gode råd for en kompilatorskriver

IN1010 våren 2018 Tirsdag 15. mai. Repetisjon av subklasser og tråder. Stein Gjessing Institutt for informatikk Universitetet i Oslo

INF2100. Oppgaver 26. september til 1. oktober 2007

Innlesning fra tastatur med easyio. INF1000 høst Vi må først skrive i toppen av programmet: import easyio.*;

JAVA Oppsummering for IS-102. Even Åby Larsen

Transkript:

Kapittel 8: Programutvikling Redigert av: Khalid Azim Mughal (khalid@ii.uib.no) Kilde: Java som første programmeringsspråk (3. utgave) Khalid Azim Mughal, Torill Hamre, Rolf W. Rasmussen Cappelen Akademisk Forlag, 2006. ISBN: 82-02-24554-0 http://www.ii.uib.no/~khalid/jfps3u/ (NB! Boken dekker opptil Java 6, men notatene er oppdatert til Java 7.) 12/7/2012 8: Programutvikling 8-1/26 Emneoversikt Formulering av problemstilling Enkel testing med assert Implementasjon som oppfyller test Test endring av objekt tilstand Kjøring av test før implementering av funksjonalitet Implementasjon for endring av tilstand Synliggjøre behovet for en bedre implementasjon med tester Implementere ny funksjonalitet forventet av testene Meldinger ved feilende tester Bedre meldinger ved feilende tester Testrammeverket JUnit Hjelpemetoder for testing i JUnit Feilmeldinger fra JUnit Refaktorering av programkode Før refaktorering av programkode Etter refaktorering av programkode Kontrakter To implementasjoner av en kontrakt Klassebibliotek Import av klassenavn Import av statiske medlemsnavn Utforming bibliotek og rammeverk Innkapsling Adgangsmodifikatorer for pakkemedlemmer Adgangsmodifikatorer for klassemedlemmer Programmerbart grensesnitt JFPS3U 8: Programutvikling 8-2/26

Formulering av problemstilling Strategispillet fire-på-rad (a) En brikke blir sluppet ned i første kolonne i et tomt spillebrett. Hvor havner brikken? JFPS3U 8: Programutvikling 8-3/26 Enkel testing med assert public class TestSpillebrett { public static void main(string[] args) { testtomrute(); public static void testtomrute() { Spillebrett brett = new Spillebrett(); // Nederste rad har indeks 0. int rad = 0; // Kolonne lengst til venstre har også indeks 0 int kolonne = 0; (a) // Punktum ('.') nedfeller tom rute. assert brett.brikkeved(kolonne, rad) == '.'; JFPS3U 8: Programutvikling 8-4/26

Implementasjon som oppfyller test Test: assert brett.brikkeved(kolonne, rad) == '.'; Implementasjon: public class Spillebrett { char brikkeved(int kolonne, int rad) { return '.'; JFPS3U 8: Programutvikling 8-5/26 Test: Test endring av objekt tilstand public static void testslippbrikke() { Spillebrett brett = new Spillebrett(); int kolonne = 0; brett.slippbrikkenedkolonne('x', kolonne); // Brikken skal nå ligge i kolonnen lengst til venstre på nederste rad: assert brett.brikkeved(0, 0) == 'X'; Kompileringsfeil: TestSpillebrett.java:22: cannot find symbol symbol : method slippbrikkenedkolonne(char,int) location: class Spillebrett brett.slippbrikkenedkolonne('x', kolonne); ^ 1 error 1 warning JFPS3U 8: Programutvikling 8-6/26

Kjøring av test før implementering av funksjonalitet Ny implementasjon som kompilerer rett: public class Spillebrett { char brikkeved(int kolonne, int rad) { return '.'; tom implementasjon void slippbrikkenedkolonne(char brikke, int kolonne) { Feil ved kjøring av test: > java -enableassertions TestSpillebrett Exception in thread "main" java.lang.assertionerror at TestSpillebrett.testSlippBrikke(TestSpillebrett.java:24) at TestSpillebrett.main(TestSpillebrett.java:5) > JFPS3U 8: Programutvikling 8-7/26 Implementasjon for endring av tilstand fungerer kun for en rute public class Spillebrett { char ruteinnhold = '.'; '.' char brikkeved(int kolonne, int rad) { return ruteinnhold; (a) void slippbrikkenedkolonne(char brikke, int kolonne) { ruteinnhold = brikke; Test er vellykket fordi kun tilstanden til en rute blir testet. JFPS3U 8: Programutvikling 8-8/26

Synliggjøre behovet for en bedre implementasjon med tester Inneværende implementasjon har begrensninger. Inneværende tester belyser ikke disse begrensningene. Lag en ny test som illustrerer behovet for ny funksjonalitet i implementasjonen. O X public static void testslippbrikke() { Spillebrett brett = new Spillebrett(); brett.slippbrikkenedkolonne('x', 0); (a) brett.slippbrikkenedkolonne('o', 2); assert brett.brikkeved(0, 0) == 'X'; assert brett.brikkeved(1, 0) == Spillebrett.TOM_RUTE; assert brett.brikkeved(2, 0) == 'O'; assert brett.brikkeved(0, 1) == Spillebrett.TOM_RUTE; JFPS3U 8: Programutvikling 8-9/26 Implementere ny funksjonalitet forventet av testene public class Spillebrett { public static final char TOM_RUTE = '\u0000'; char[][] ruteinnhold = new char[7][6]; Spillebrett() { assert ruteinnhold[0][0] == TOM_RUTE; char brikkeved(int kolonne, int rad) { return ruteinnhold[kolonne][rad]; void slippbrikkenedkolonne(char brikke, int kolonne) { int nedersteledigerad = 0; ruteinnhold[kolonne][nedersteledigerad] = brikke; JFPS3U 8: Programutvikling 8-10/26

Meldinger ved feilende tester Påstand med vanlig assert nøkkelord: Linje 48: assert brett.brikkeved(3, 0) == 'X'; Feilmelding forteller linjenummer, men ikke hvilken brikkeverdi som lå ved (3, 0): Exception in thread "main" java.lang.assertionerror at TestSpillebrett.testStabling(TestSpillebrett.java:48) at TestSpillebrett.main(TestSpillebrett.java:6) JFPS3U 8: Programutvikling 8-11/26 Hjelpefunksjon: Bedre meldinger ved feilende tester Linje 40: static void påstålikhet(string melding, char forventet, char faktisk) { if (forventet!= faktisk) { System.err.printf("Likhetsfeil: %s: Forventet <%s>, men fikk <%s>\n", melding, forventet, faktisk); assert forventet == faktisk; Påstand med hjelpefunksjon: Linje 56: påstålikhet("første sluppet", 'X', brett.brikkeved(3, 0)); Feilmelding med nyttig informasjon: Likhetsfeil: Første sluppet: Forventet <X>, men fikk <O> Exception in thread "main" java.lang.assertionerror at TestSpillebrett.påståLikhet(TestSpillebrett.java:40) at TestSpillebrett.testStabling(TestSpillebrett.java:56) at TestSpillebrett.main(TestSpillebrett.java:6) JFPS3U 8: Programutvikling 8-12/26

Testrammeverket JUnit JUnit er et av de mest populære testrammeverkene for Java. Har en samling av hjelpemetoder for testing av programmer. Last ned et zip-arkiv med nyeste versjon av JUnit ved å følge «Download»-lenken på nettsiden http://www.junit.org/. Pakk ut zip-arkivet til en egnet katalogsti. Legg katalogsti/junit.jar til miljøvariabelen CLASSPATH. Sjekk først om JUnit er skikkelig installert: > java junit.textui.testrunner -v JUnit 4... > JFPS3U 8: Programutvikling 8-13/26 Hjelpemetoder for testing i JUnit junit.framework.assert Påstå likhet: static void assertequals(datatype forventet, datatype faktisk) static void assertequals(string beskjed, datatype forventet, datatype faktisk) Påstå sannhet: static void asserttrue(string beskjed, bool betingelse) Påstå usannhet: static void assertfalse(string beskjed, bool betingelse) Rapporter feil: static void fail(string beskjed) JFPS3U 8: Programutvikling 8-14/26

Feilmeldinger fra JUnit > java -enableassertions junit.textui.testrunner TestSpillebrett...F Time: 0,015 There was 1 failure: 1) teststabling(testspillebrett)junit.framework.assertionfailederror: Første sluppet expected:<x> but was:<o> at TestSpillebrett.testStabling(TestSpillebrett.java:44) at sun.reflect.nativemethodaccessorimpl.invoke0(native Method) at sun.reflect.nativemethodaccessorimpl.invoke(nativemethodaccessorimpl.java:39) at sun.reflect.delegatingmethodaccessorimpl.invoke(delegatingmethodaccessorimpl.java:25) FAILURES!!! Tests run: 3, Failures: 1, Errors: 0 Fremdriftsindikator (rød pga. feil) Antall tester som kastet unntak Totalt antall tester Antall tester som feilet JFPS3U 8: Programutvikling 8-15/26 Før refaktorering av programkode static String spillebrettradsomtekst(spillebrett brett, int rad) { final int ANTALL_KOLONNER = 7; final int SISTE_KOLONNE = ANTALL_KOLONNER - 1; String radtekst = " "; for (int kolonne = 0; kolonne < SISTE_KOLONNE; ++kolonne) { char tilstand = brett.brikkeved(kolonne, rad); if (tilstand == Spillebrett.TOM_RUTE) { radtekst += "."; else { radtekst += tilstand; radtekst += " "; char tilstand = brett.brikkeved(siste_kolonne, rad); if (tilstand == Spillebrett.TOM_RUTE) { radtekst += "."; else { radtekst += tilstand; return radtekst + " "; duplisert programkode JFPS3U 8: Programutvikling 8-16/26

Etter refaktorering av programkode static String spillebrettradsomtekst(spillebrett brett, int rad) { final int ANTALL_KOLONNER = 7; final int SISTE_KOLONNE = ANTALL_KOLONNER - 1; String radtekst = " "; for (int kolonne = 0; kolonne < SISTE_KOLONNE; ++kolonne) radtekst += spillebrettrutesomtekst(brett, kolonne, rad) + " "; return radtekst + spillebrettrutesomtekst(brett, SISTE_KOLONNE, rad) + " "; static char spillebrettrutesomtekst(spillebrett brett, int kolonne, int rad) { char tilstand = brett.brikkeved(kolonne, rad); if (tilstand == Spillebrett.TOM_RUTE) return '.'; return tilstand; JFPS3U 8: Programutvikling 8-17/26 Kontrakter Eksempel: interface ISpiller { void utførtrekk(spillebrett brett); Man ikke opprette objekter av ISpiller-kontrakten. Man kan lage objekter av klasser som implementerer ISpiller-kontrakten. Man kan referere til disse objektene med felt og lokale variabler av referansetypen ISpiller. Det kan finnes mer enn en implementasjon som oppfyller ISpiller-kontrakten. JFPS3U 8: Programutvikling 8-18/26

To implementasjoner av en kontrakt public class TerminalSpiller implements ISpiller { SpillTekstGrensesnitt grensesnitt; TerminalSpiller(SpillTekstGrensesnitt grensesnitt) { this.grensesnitt = grensesnitt;) public void utførtrekk(spillebrett brett) { assert!brett.erspillferdig(); assert brett == grensesnitt.brett; brett.slippbrikkenedkolonne(brett.nestebrikke(), grensesnitt.beomkolonnevalg()); public class RandomSpiller implements ISpiller { public void utførtrekk(spillebrett brett) { assert!brett.erspillferdig(); int valg; do { valg = (int) (Math.random() * Spillebrett.KOLONNE_ANTALL); while (!brett.ergyldigkolonnevalg(valg)); brett.slippbrikkenedkolonne(brett.nestebrikke(), valg); JFPS3U 8: Programutvikling 8-19/26 Klassebibliotek Kildekode kan ofte utnyttes i flere programmer. Kode som man identifiserer som generelt nyttig blir vanligvis skrevet om til klassebiblioteker. Eksempler på klassebibliotek: JUnit. Java sitt standard klassebibliotek. Klassebiblioteker bør utformes med omhu. Biblioteker bør: være lette å forstå og bruke kunne brukes uten å endre på kode i biblioteket ikke uten god grunn begrense situasjonene hvor det er mulig å bruke biblioteket JFPS3U 8: Programutvikling 8-20/26

Import av klassenavn Uten import setning må klasser oppgies med fullt navn: java.util.scanner inndata = new java.util.scanner(); Import av klassenavn gjør bruk av fullt navn unødvendig: import java.util.scanner... Scanner inndata = new Scanner(); Man kan importere alle klassenavnene fra en pakke samtidig: import java.util.*;... Scanner inndata = new Scanner(); Formatter formatter = new Formatter(); JFPS3U 8: Programutvikling 8-21/26 Import av statiske medlemsnavn Uten importsetningen må statiske felt og metoder refereres til med navnet til klassen medlemmene befinner seg i: long fib = Math.round(Math.pow(0.5 + Math.sqrt(5)/2, n)/math.sqrt(5)); Import av medlemsnavn gjør det unødvendig å oppgi klassenavnet: import static java.lang.math.sqrt;... long fib = Math.round(Math.pow(0.5 + sqrt(5)/2, n)/sqrt(5)); Man kan importere alle statiske medlemsnavn fra en klasse samtidig: import static java.lang.math.*;... long fib = round(pow(0.5 + sqrt(5)/2, n)/sqrt(5)); JFPS3U 8: Programutvikling 8-22/26

Utforming bibliotek og rammeverk Organisér klassene i pakker: En pakkedeklarasjon kan angis på starten av kildekodefiler for å deklarere at alle klasser, kontrakter og oppramstyper deklarert i filen tilhører den angitte pakken. package spill.terminal.lettspill; // Fil: spill/terminal/lettspill.java public class LettSpill { /*... */ ; Kompilering: > javac spill/terminal/lettspill.java Kjøring: > java -ea spill.terminal.lettspill Et rammeverk er et klassebibliotek som i tillegg til å ta imot innkommende metodekall også utfører utgående metodekall. Rammeverk tillater definering nye klasser utenfor klassebiblioteket, som har metoder som vil bli utført når rammeverket gjør visse operasjoner. JFPS3U 8: Programutvikling 8-23/26 Innkapsling og adgangsmodifikatorer for pakkemedlemmer Innkapsling (eng. encapsulation) er en abstraksjonsteknikk. Innkapsling hjelper oss med å redusere kompleksiteten til koden. Utform programkode hvor essensiell informasjon er lett tilgjengelig. Kun relevant informasjon bør være synlig utad. Skjul detaljer. Operasjonene og dataene de jobber på bør være sterkt sammenknyttet. Fortell andre objekter hva de skal gjøre. Ikke spør dem om tilstand. En enkel form for innkapsling er å skjule informasjon ved bruk av adgangsmodifikatorer. Adgangs-kontekst public Pakkesynlighet: ingen adgangs-modifikator I samme pakke Ja Ja I andre pakker Ja Nei JFPS3U 8: Programutvikling 8-24/26

Adgangsmodifikatorer for klassemedlemmer Adgangsmodifikatorene public, protected og private har blitt brukt for å skjule felter og metoder i klassen som ikke behøver å være allment tilgjengelig. Adgangskontekst public protected pakkesynlighet: ingen adgangsmodifikator (package) private I samme klasse Ja Ja Ja Ja I andre klasser i Ja Ja Ja Nei samme pakke Fra subklasser i Ja Ja Nei Nei andre pakker Fra annen kode i andre pakker Ja Nei Nei Nei JFPS3U 8: Programutvikling 8-25/26 Programmerbart grensesnitt Programmerbart grensesnitt (eng. Application Programming Interface, API) Den eksternt synlige delen av et klassebibliotek Klassebibliotek brukes av mange bør være «stabilt». Programkode som bruker APIet må sjeldent skrives om. Endringer man kan gjøre i et klassebibliotek, uten fare for å introdusere kompileringsfeil i programkode som bruker APIet til klassebiblioteket: legge til helt nye pakker, kontrakter, klasser. legge til nye felter, metoder og konstruktører til klasser. Slette felter og metoder som ikke er synlige, dvs. alle medlemmer som ikke er public eller protected. Slette eller endre klasser som ikke er synlige, dvs. alle klasser som ikke er public. Gjøre felter og metoder mer synlige ved å endre adgangsmodifikatoren. Endre implementasjonen av metoder. JFPS3U 8: Programutvikling 8-26/26