"Nelsons kaffebutikk" et eksempel på systemutvikling med objekter Originale lysark av Jens Kaasbøll - mindre endringer av G. Skagestein og Knut Hegna IN105-javaNelson-1
Nelsons kaffebutikk Området som programmet skal handle om Oppgavene som brukerne (kundene) skal gjøre Testrekkefølge: En funksjon om gangen Brukerevaluering Programutførelse og test Kompilering og retting av syntaksfeil Analyse Hva består området av? Hvilke funksjoner skal programmet dekke? Kravspesifikasjon Design Hvordan skal programmet struktureres? Program og datastruktur Kodingsrekkefølge En funksjon om gangen En klasse om gangen Koding Velge array, evt. flere dimensjoner HashMap Nelsons kaffebutikk modifisert (JavaGently 8.6) IN105-javaNelson-2
Analyse Lageradministrasjon (inventory) Mange kaffeslag (blend, kind, coffee, type): Java, columbiansk, VIP, kenyansk, o Hvert kaffeslag har et navn, en pris, mengde på lager, minimumsnivå, strekkode Hvert kaffeslag leveres i partier (batches) o Hvert parti har en mengde og en utløpsdato Funksjoner o Klargjøre for mottak av partier o Vise data o Sjekke minimumsbeholdning o Sjekke hvor mye tilgjengelig o Endre pris o Legge til et parti til beholdning o Selge kaffe o Fjern for gammel kaffe IN105-javaNelson-3
Analyse: Modell av butikken Ett kaffelager Flere slag (type) Flere partier for hvert slag KaffeLager KaffeSlag KaffeParti mange mange IN105-javaNelson-4
Design: Metoder i KaffeLager-objektet KaffeLager JavaGently side 235 selg() nyttparti() slagene viskaffe() nyttkaffeslag() KaffeLager() utførordre() sjekkutløpsdato() lagerverdi() lesfrafil() skrivpåfil() Det lages bare en instans (et objekt) av denne klassen IN105-javaNelson-5
KaffeSlag Design: Metoder i de øvrige objektene Java JavaGently side 235 KaffeSlag() vispåskjerm() navn KaffeParti sjekkminimumsbeholdning(int dato) endrepris() nyttparti() pris 83.50 parti KaffeParti() double selg() mengde 60.0 Boolean sjekkutløp(int dato) selg() sjekkutløp(int dato) lesfra(stream innfil) skrivpå(stream utfil) vispåskjerm double tilgjengelig() lesfra (Stream innfil) skrivpå (Stream utfil) utløpsdato 19990723 IN105-javaNelson-6
Design: Velge datastruktur Array HashMap Lengde Fast Ubegrenset Ordning 0 til max-1 Ingen 2 og flerdimensjonale Gjennomløp Enkel for-løkke Iteration Sette inn objekt Tilordning put Oppdatere antall Ta ut objekt Tilordning, evt. flytting, remove oppdatere antall Søking Ingen get Kaffeslagene Kaffepartiene 1 Ubegrenset antall 1 Ubegrenset antall 2 Ingen ordning 2 Stadig nye inn og ut 3 Gjennomløpes ved les/skriv på fil 3 Kronologisk ordning 4 Opprette og fjerne 4 Gjennomløpes ved les/skriv på fil 5 Søking etter navnet 5 Opprette nye, fjerne eldste HashMap 6 Ingen søking, ta neste Array best 3 6, HashMap 1 2 IN105-javaNelson-7
Dato og tid Java har klasser for dette i pakken util + Mange muligheter Tungt å sette seg inn i Kan bruke int int dato1, dato 2; dato1 < dato2 ønsker vi skal bety at dato1 kommer før dato2. Leser derfor alle datoer inn fra terminal og fil på formen ååååmmdd IN105-javaNelson-8
KaffeLager KaffeSlag Modellen KaffeParti slagene Kenyan Java Columbian navn pris 83.50 navn pris 78.90 navn pris 62.50 parti parti parti utløpsdato 19990723 mengde 60.0 utløpsdato 19990808 mengde 30.0 utløpsdato 19990601 mengde 20.0 utløpsdato 19991015 mengde 80.0 IN105-javaNelson-9
Kontrolløren KaffeKontroll main KaffeLager kl = new KaffeLager(); kl.utførordreogtavarepådata(); kl IN105-javaNelson-10
KaffeLager Konstruktør og utførordreogtavarepådata KaffeLager() slagene = new HashMap(); in = new Stream (System.in); filnavn = "kaffe.data"; slagene void utførordreogtavarepådata() lesfrafil(); utførordre(); skrivpåfil(); in filnavn kaffe.data IN105-javaNelson-11
Filformat 3 Columbian 62.5 2 300.0 20020101 Antall kaffeslag Navn på kaffeslag Pris Antall partier Mengde Utløpsdato 70.0 20020101 Java 83.5 1 20.0 20000101 Kenyan 78.9 1 80.0 20000601 IN105-javaNelson-12
KaffeLager void lesfrafil() lesfrafil slagene KaffeSlag k; innfil = new Stream (filnavn, Stream.READ ); int antslag = innfil.readint( ); for (int i=1; i<=antslag; i++) { k = new KaffeSlag( ); k.lesfra(innfil); slagene.put(k.navn,k); } // Slutt for filnavn k innfil Java navn pris 83.50 første 1 void lesfra(stream innfil) siste 1 navn = innfil.readstring( ); pris = innfil.readdouble( ); siste = innfil.readint( ); for (int i=1; i<=siste; i++) { parti[i] = new KaffeParti(); parti[i].lesfra( ); innfil } KaffeSlag maxpartier 100 KaffeSlag() parti = new KaffeParti[maxPartier+1]; parti filnavn kaffe.data KaffeParti void lesfra(stream innfil) mengde = innfil.readdouble( ); utløpsdato = innfil.readint( ); innfil mengde 60.0 utløpsdato 19990723 IN105-javaNelson-13
Testing For å teste en funksjon, må vi ha en måte å observere hva den gjør lesfrafil lager endringer i modellen i primærlageret, så vi kan ikke vite hva den gjør før vi lager utskriftsmetoder IN105-javaNelson-14
Etter å ha klarlagt funksjonalitet datastruktur og programstruktur Rekkefølge i koding skal de enkelte metoder defineres og kodes. To veier: En funksjon av gangen med nødvendige metoder i hver klasse for å kunne utføre funksjonen o Eks: Innlesing i personregister + Kan teste hver funksjon hvis vi har utskriftsrutiner Må holde oversikt over variable i mange klasser Vil følge denne rekkefølgen i Kaffebutikken En klasse av gangen med de metodene som trengs for å utføre alle funksjoner + Konsentrasjon om variablene i denne klassen Må kunne forutse hva en metode i en annen klasse kan gjør IN105-javaNelson-15
Organisering av metodene Standard framgangsmåte for koding av en av de ordrene programmet skal utføre er å lage en metode i hvert objekt som gjør sin jobb med å søke / lese av / oppdatere variablene i sitt objekt for denne ordren Metoden i KaffeLager kaller metoden i KaffeSlag som igjen kaller metoden i KaffeParti KaffeLager KaffeSlag KaffeParti selg() mange selg() mange selg() IN105-javaNelson-16
KaffeLager KaffeLager skrivpåfil void skrivpåfil() KaffeSlag k; utfil = new Stream (filnavn, Stream.WRITE); utfil.println(slagene.size()); Iterator it = slagene.values( ).iterator ( ); while (it.hasnext ( )) { k = (KaffeSlag) e.next(); k.skrivpå( utfil ); } utfil.close( ); k slagene filnavn innfil filnavn kaffe.data IN105-javaNelson-17
KaffeSlag og KaffeParti skrivpå Java KaffeSlag navn pris 83.50 første 1 void skrivpå(stream utfil) utfil.println(navn+" "+pris+" "+antallpartier()); for (int i=første; i<=siste; i++) parti[i].skrivpå(utfil); utfil siste 3 maxpartier 100 parti filnavn void skrivpå (Stream utfil) kaffe.data KaffeParti utfil utfil.println(mengde+" "+utløpsdato); mengde 60.0 utløpsdato 19990723 IN105-javaNelson-18
KaffeLager utførordre void utførordre () String ordre="0"; while (!ordre.equals( "A" )) { System.out.println ("Ordre (Vis all kaffen, " + "nytt Kaffeslag, nytt Parti, " + "Selg, sjekk Utløpsdato, " + "Lagerverdi, Avslutt)?" ); ordre = in.readstring( ); if ( ordre.equals ( "V" )) { viskaffe ( ); } else if ( ordre.equals ( "K" )){ nyttkaffeslag( ); } else if ( ordre.equals ( "P" )){ nyttparti( ); } else if ( ordre.equals ( "S" )){ selg( ); } else if ( ordre.equals ( "U" )){ sjekkutløpsdato( ); } else if ( ordre.equals ( "L" )){ lagerverdi( ); } } // Slutt kommando-løkka slagene in IN105-javaNelson-19
KaffeLager KaffeLager viskaffe void viskaffe() KaffeSlag k; Iterator it = slagene.values( ).iterator( ); while ( it.hasnext( )) { k = (KaffeSlag) it.next( ); k.vispåskjerm( ); } k slagene IN105-javaNelson-20
KaffeSlag og KaffeParti vispåskjerm Java KaffeSlag navn pris 83.50 første 1 siste 3 maxpartier 100 void vispåskjerm() System.out.println( ); System.out.println(navn); System.out.print( "Pris: kr" + Stream.format(pris,6,2)); System.out.println(" Antall partier: " + antallpartier( )); System.out.println(" Mengde Utløpsdato"); for (int i = første; i <= siste; i++) parti[i].vispåskjerm( ); } // slutt vispåskjerm parti void vispåskjerm() System.out.println( Stream.format (mengde, 6, 1) + " " + utløpsdato); KaffeParti mengde 60.0 utløpsdato 19990723 IN105-javaNelson-21
KaffeLager nyttkaffeslag KaffeLager void nyttkaffeslag( ) throws IOException System.out.print( "Navn? " ); String navn = in.readstring( ); System.out.print( "Pris? " ); double pris = in.readdouble( ); slagene.put(navn, new KaffeSlag(navn,pris)); pris 72.50 navn slagene Brazilian KaffeSlag må ha en konstruktør som tar verdier gjennom parametre IN105-javaNelson-22
Nytt kaffeslag-objekt Brazilian KaffeSlag navn pris 72.50 første 1 KaffeSlag(String n, double p) siste 0 // Konstruktør som får verdier tilsendt navn = n; pris = p; parti = new KaffeParti[maxPartier+1]; maxpartier 100 parti IN105-javaNelson-23
Design: Invariant for parti-arrayen Nye partier settes inn sist i parti int siste er indeksen for siste (nyeste) parti som er satt inn Gamle partier tas ut fra begynnelsen int første er indeksen for første (eldste) parti som stadig er med int maxpartier er høyeste indeks i parti Invariant: 1<=i<første: KaffeParti[i] = første<=i<=siste: KaffeParti[i]!= siste<i<=maxpartier: KaffeParti[i] = Når siste==maxpartier og det kommer et nytt parti, flyttes alle partiene først i arrayen, slik at første==1 0 1 første siste maxpartier IN105-javaNelson-24 parti
KaffeLager KaffeLager selg void selg() KaffeSlag k; String navn; System.out.print ( "Kaffeslag? " ); navn = in.readstring( ); k slagene // Leter fram kaffeslaget med dette navnet: navn k = (KaffeSlag) slagene.get(navn); if (k!=) { // Et kaffeslag med dette navnet ble funnet Java k.selg( ); } else System.out.println( "Beklager ingen kaffe som heter " + navn ); IN105-javaNelson-25
KaffeSlag selg void selg() navn pris 83.50 Java parti double vilselge; vilselge System.out.print( "Hvor mange kilogram? " ); 100 vilselge = in.readdouble( ); if (vilselge > pålager( )) System.out.println( "Beklager, vi har bare " + pålager( )+ " på lager nå" ); else { double solgtnå = 0, igjenåselge = vilselge; for (int i = første; igjenåselge > 0; i++) { solgtnå = parti[i].selg( igjenåselge ); igjenåselge = igjenåselge - solgtnå; } fjerntommepartier( ); } double pålager() double beholdning=0; for (int i=første; i<=siste; i++) { første 5 siste 9 KaffeSlag maxpartier 100 solgtnå 0 igjenåselge 100 beholdning 0 if (parti[i]!= ) beholdning = beholdning + parti[i].mengde; } // Slutt for return beholdning; 0 1 første siste maxpartier IN105-javaNelson-26
KaffeParti KaffeParti selg Testdata for salg; double selg(double vilselge) Et kaffeparti som double solgt; if (mengde>=vilselge) { mengde = mengde-vilselge; return vilselge; } else { solgt = mengde; mengde = 0; return solgt; } vilselge 60 ikke fins Mer enn på lager Mer enn det er i ett parti Mindre enn det første partiet for salg mengde 60.0 utløpsdato 19990723 IN105-javaNelson-27
KaffeSlag fjerntommepartier Java KaffeSlag navn void fjerntommepartier() 83.50 5 9 100 parti for (int i=første; i<=siste; i++) { if (parti[i]!= ) { // Unødvendig test hvis invarianten holder if (parti[i].mengde==0) { parti[i]=; første = i+1; } } // Slutt if (parti[i]!= ) } // Slutt for 0 1 første siste maxpartier Testes enklest ved å sette maxpartier til 3 eller et annet lite tall IN105-javaNelson-28
KaffeLager KaffeLager sjekkutløpsdato void sjekkutløpsdato( ) int dato; System.out.print( "Dato (ååååmmdd)? " ); dato = in.readint( ); KaffeSlag k; Iterator it = slagene.values( ).iterator( ); while ( it.hasnext( )) { k = (KaffeSlag) it.next( ); k.sjekkutløpsdato(dato); } // slutt while k dato 19990315 slagene IN105-javaNelson-29
KaffeSlag sjekkutløpsdato Java KaffeSlag navn pris 83.50 første 7 double sjekkutløpsdato(int dato) for (int i=første; i<=siste; i++) { if (parti[i].utløpsdato<dato) { parti[i]=; første = i+1; } // Slutt if } // Slutt for siste 9 maxpartier 100 dato 19990315 parti 0 1 første siste maxpartier IN105-javaNelson-30
navn void nyttparti() pris 83.50 Java første 7 KaffeSlag siste 9 maxpartier 100 if (første==1 & siste==maxpartier) { System.out.println("Beklager, programmet er fullt"); } else { if (siste==maxpartier) { // Her er første>1 // Flytter alle objektene slik at de starter i parti[1] for (int i=første; i<=siste; i++) parti[i-første+1] = parti[i]; siste = antallpartier(); første = 1; }; siste++; parti[siste] = new KaffeParti(); parti[siste].lesfraterminal(); } // Slutt else KaffeSlag nyttparti parti 0 1 første siste maxpartier IN105-javaNelson-31
KaffeParti lesfraterminal void lesfraterminal() System.out.print ("Mengde? "); mengde = in.readdouble( ); System.out.print ("Utløpsdato (ååååmmdd)? "); utløpsdato = in.readint( ); mengde 60.0 utløpsdato 19990723 KaffeParti Fullstendig program via programeksempelsida IN105-javaNelson-32