Mallivastaukset, osatehtävä 2: Verkkokauppa

Seuraavassa esitetään joukko erilaisia tapoja ratkaista annetut tehtävät. Myös muut ratkaisut ovat mahdollisia.

Osatehtävä 2.1: Tuotteet

Abstrakti luokka Tuote

Tehtävänanto

Toteuta abstrakti luokka Tuote, joka esittää yksittäistä verkkokaupan myymää tuotetta. Luokalla on seuraavat ominaisuudet:

String tunnus
Tuotteen yksikäsitteinen tunniste, jota kauppa käyttää tuotteiden erottamiseen toisistaan.
String kuvaus
Tuotteen selväkielinen kuvaus, joka voidaan näyttää asiakkaalle.

Luokalla on seuraavat metodit:

Luontimetodi Tuote(String tunnus, String kuvaus)
Luo uuden tuotteen, jolla on parametrina annettu tunnus ja kuvaus.
String tunnus()
Palauttaa tuotteen tunnuksen.
String kuvaus()
Palauttaa tuotteen kuvauksen.

Vastaus

Ratkaisu on muuten aivan suoraviivainen, mutta Tuote on laitettava toteuttamaan rajapinta Comparable, jotta tuotteiden järjestäminen toimisi osatehtävässä 2.3. Metodin compareTo(Object) totetutus vertaa tunnus-kenttiä String-luokan metodilla compareTo(Object). Poikkeus ClassCastException syntyy, jos annettu olio ei ole Tuote.

public abstract class Tuote implements Comparable {
    protected String tunnus;
    protected String kuvaus;

    public Tuote(String tunnus, String kuvaus) {
	this.tunnus = tunnus;
	this.kuvaus = kuvaus;
    }

    public String tunnus() {
	return tunnus;
    }

    public String kuvaus() {
	return kuvaus;
    }

    public int compareTo(Object o) throws ClassCastException {
	return tunnus().compareTo(((Tuote)o).tunnus());
    }
}
      

Luokka Kirja

Tehtävänanto

Tee Tuote-luokan alaluokka Kirja. Luokalla on seuraavat ominaisuudet (Luokasta Tuote perittyjen lisäksi):

String isbn
Kirjan ISBN-numero.
String nimi
Kirjan nimi.
SortedSet kirjoittajat
Joukko, jossa on kirjan kirjoittajien nimet muodossa "Sukunimi, Etunimi". Nimet ovat aakkosjärjestyksessä.

Luokalla on seuraavat metodit:

Luontimetodi Kirja(String tunnus, String nimi, String[] kirjoittajat, String isbn)
Luo uuden kirjan, jolla on parametrina annettu tunnus, isbn-numero, nimi ja kirjoittajat. Kirjoittajat annetaan String-taulukossa. Luontimetodi muodostaa niistä järjestetyn joukon ja tallettaa ominaisuusmuuttujaan kirjoittajat. Tuotteen kuvausta ei anneta parametrina, vaan se muodostetaan luontimetodissa kirjan ja kirjoittajien nimistä sekä ISBN-numerosta.
String isbn()
Palauttaa kirjan isbn-numeron.
String nimi()
Palauttaa kirjan nimen.
SortedSet kirjoittajat()
Palauttaa kirjan kirjoittajat.
String toString()
Palauttaa kirjaa kuvaavan (lyhyen) merkkijonon. Voi muodostua esim. kirjan nimestä.

Vastaus

Tässä ainoa suurempi ongelma on tuotekuvauksen muodostaminen yläluokan Tuote luontimetodia varten. Kirja-luokan luontimetodi saa parametrinaan kirjan nimen, taulukon kirjoittajien nimiä ja isbn:n. Näistä pitäisi muodostaa järjellinen kirjan kuvaus, joka annetaan super-kutsulle parametrina.

Seuraavassa ongelma on ratkaistu ottamalla käyttöön protected määreellä varustettu sisäinen luontimetodi, joka ottaa parametrinaan kirjoittajien nimiä sisältävän taulukon tilalta SortedSet-tyyppisen kokoelman, jossa kirjoittajat ovat aakkosjärjestyksessä. Varsinainen luontimetodi kutsuu sisäistä luontimetodia. Sisäinen luontimetodi kutsuu apumetodia siistiKirjoittajat, joka muodostaa kirjoittajakokoelmasta siistin merkkijonon. Tämä merkkijono yhdistetään muihin parametreihin ja välitetään luokan Tuote luontimetodille super-kutsussa.

Myös muunlaiset ratkaisut ovat mahdollisia. Tässä sisäistä luontimetodia on käytetty myös esimerkin vuoksi.

import java.util.Arrays;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;

public class Kirja extends Tuote {
    protected String nimi;
    protected SortedSet kirjoittajat;
    protected String isbn;

    // Apumetodi
    protected static String siistiKirjoittajat(SortedSet kirjoittajat) {
	String tulos = "";
	Iterator it = kirjoittajat.iterator();
	while (it.hasNext()) {
	    String nimi = (String)it.next();
	    tulos = tulos + nimi;
	    if (it.hasNext()) {
		tulos = tulos + ", ";
	    }
	}
	return tulos;
    }

    // Sisäinen luontimetodi
    protected Kirja(String tunnus, String nimi, SortedSet kirjoittajat, 
		    String isbn) {
	super(tunnus, siistiKirjoittajat(kirjoittajat)
	      + ": " + nimi
	      + ". ISBN: " + isbn);
	this.nimi = nimi;
	this.kirjoittajat = kirjoittajat;
	this.isbn = isbn;
    }

    public Kirja(String tunnus, String nimi, String[] kirjoittajat, String isbn) {
	this(tunnus, nimi, new TreeSet(Arrays.asList(kirjoittajat)), isbn);
    }

    public String isbn() {
	return isbn;
    }

    public String nimi() {
	return nimi;
    }

    public SortedSet kirjoittajat() {
	return kirjoittajat;
    }

    public String toString() {
	return "Kirja[" + tunnus() + ", " + nimi() + "]";
    }
}
      

Luokka CD

Tehtävänanto

Tee Tuote-luokan alaluokka CD. Sillä on Tuote-luokassa määriteltyjen attribuuttien lisäksi seuraavat ominaisuudet:

String nimi
Levyn nimi.
String esittäjä
Esittäjän nimi.

Luokalla on seuraavat metodit:

Luontimetodi CD(String tunnus, String nimi, String esittäjä)
Luo uuden CD:n, jolla on parametrina annettu tunnus, nimi ja esittäjä. Kuvausta ei tässäkään anneta parametrina, vaan se muodostetaan luontimetodissa CD:n ja esittäjän nimistä.
String nimi()
Levyn nimi.
String esittäjä()
Palauttaa esittäjän nimen.
String toString()
Palauttaa CD:tä kuvaavan (lyhyen) merkkijonon. Voi muodostua esim. CD:n nimestä.

Vastaus

Tämä on suoraviivaista koodia.

public class CD extends Tuote {
    protected String nimi;
    protected String esittäjä;

    public CD(String tunnus, String nimi, String esittäjä) {
	super(tunnus, esittäjä + ": " + nimi);
	this.nimi = nimi;
	this.esittäjä = esittäjä;
    }

    public String nimi() {
	return nimi;
    }

    public String esittäjä() {
	return esittäjä;
    }

    public String toString() {
	return "CD[" + tunnus() + ", " + nimi() + "]";
    }
}
      

Osatehtävä 2.2: Luokka Valikoima

Tehtävänanto

Kirjoita luokka Valikoima, joka sisältää verkkokaupan tarjoamat tuotteet, jotka ovat siis kirjoja ja CD:itä. Luokalla on seuraavat ominaisuudet:

Map tuotteet
Sisältää valikoimaan kuuluvat tuotteet. Mapin avaimina ovat tuotteiden tunnukset ja avaimia vastaavina arvoina tuoteoliot.

Luokalla on seuraavat metodit:

Luontimetodi Valikoima()
Luo uuden tyhjän valikoimaolion.
void lisääTuote(Tuote uusi)
Lisää uuden tuotteen valikoimaan.
void poistaTuote(Tuote tuote)
Poistaa tuotteen valikoimasta.
Collection tuoteKokoelma()
Palauttaa valikoimaan kuuluvat tuotteet kokoelmana (siis ei Mapina).
Collection kirjaKokoelma()
Palauttaa valikoimaan kuuluvat kirjat kokoelmana.
Collection CDKokoelma()
Palauttaa valikoimaan kuuluvat CDt kokoelmana.
Tuote haeTuote(String tunnus)
Palauttaa tuotteen, jonka tunnus on tunnus. Jos sitä ei löydy, palauttaa arvon null.
Set haeTuotteet(String s)
Hakee valikoimasta kaikki tuotteet, joiden kuvaus sisältää merkkijonon s. Palauttaa tuloksen joukkona. Merkkijonon s etsiminen kuvauksesta tapahtuu String-luokan metodilla indexOf.
String toString()
Palauttaa lyhyen kuvauksen valikoimasta.

Vastaus

Ratkaisu on pääosin suoraviivainen. Rajapinnan java.util.Map toteutukseksi on valittu luokka java.util.HashMap. Metodit kirjaKokoelma ja CDKokoelma ja toteutetaan käymällä iteraattorilla läpi kaikki tuoteKokoelma-metodin palauttamat tuotteet ja poimimalla niistä oikean tyyppiset uuteen kokoelmaan. Syntynyt kokoelma palautetaan. Metodi haeTuotteet käy läpi kaikki tuotteet ja etsii luokan String metodilla indexOf(String) kaikki tuotteet, joiden kuvaus sisältää etsityn merkkijonon.

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

public class Valikoima {
    protected Map tuotteet;
    
    public Valikoima() {
	tuotteet = new HashMap();
    }

    public void lisääTuote(Tuote t) {
	tuotteet.put(t.tunnus(), t);
    }

    public void poistaTuote(Tuote t) {
	tuotteet.remove(t.tunnus());
    }

    public Collection tuoteKokoelma() {
	return tuotteet.values();
    }

    public Collection kirjaKokoelma() {
	Collection result = new LinkedList();
	Iterator it = tuoteKokoelma().iterator();
	while (it.hasNext()) {
	    Tuote t = (Tuote)it.next();
	    if (t instanceof Kirja) {
		result.add(t);
	    }
	}
	return result;
	
    }

    public Collection CDKokoelma() {
	Collection result = new LinkedList();
	Iterator it = tuoteKokoelma().iterator();
	while (it.hasNext()) {
	    Tuote t = (Tuote)it.next();
	    if (t instanceof CD) {
		result.add(t);
	    }
	}
	return result;
	
    }

    public Tuote haeTuote(String tunnus) {
	return (Tuote)tuotteet.get(tunnus);
    }

    public Set haeTuotteet(String s) {
	Set result = new HashSet();
	Iterator it = tuoteKokoelma().iterator();
	while (it.hasNext()) {
	    Tuote t = (Tuote)it.next();
	    if (t.kuvaus().indexOf(s) >= 0) {
		result.add(t);
	    }
	}
	return result;
    }

    public String toString() {
	return "Valikoima[" + kirjaKokoelma().size() + " kirjaa, "
	    + CDKokoelma().size() + " CD:tä]";
    }
}
      

Osatehtävä 2.3: Luokka Ostoskori

Tehtävänanto

Tee luokka Ostoskori, joka sisältää asiakkaan valitsemat tuotteet. Luokalla on seuraavat ominaisuudet:

String asiakas
Asiakkaan nimi (tai muu tunniste).
List ostokset
Asiakkaan valitsemat tuotteet. Huomaa, että sama tuote voi toistua useita kertoja.

Luokalla on seuraavat metodit:

Luontimetodi Ostoskori(String asiakas)
Luo uuden tyhjän ostoskorin.
String asiakas()
Palauttaa asiakkaan nimen.
void lisääTuote(Tuote uusi)
Lisää tuotteen ostoskoriin.
void poistaTuote(Tuote tuote)
Poistaa tuotteen ostoskorista.
List tuotteet
Palauttaa ostoskorin sisältämät tuotteet lajiteltuna tuotteen tunnuksen mukaisesti. Huom! Duplikaatteja ei poistetan.
String toString()
Ostoskorin lyhyt kuvaus.

Vastaus

Ratkaisu on suoraviivainen. Rajapinnan java.util.List toteutukseksi on valittu luokka java.util.LinkedList. Metodissa tuotteet ostokset järjestetään luokan java.util.Collections metodilla sort(List). Tämä onnistuu, koska Tuote-luokkka toteuttaa rajapinnan Comparable.

import java.util.Collections;
import java.util.List;
import java.util.LinkedList;

public class Ostoskori {
    protected String asiakas;
    protected List ostokset;

    public Ostoskori(String asiakas) {
	this.asiakas = asiakas;
	ostokset = new LinkedList();
    }

    public String asiakas() {
	return asiakas;
    }

    public void lisääTuote(Tuote uusi) {
	ostokset.add(uusi);
    }

    public void poistaTuote(Tuote uusi) {
	ostokset.remove(uusi);
    }

    public List tuotteet() {
	Collections.sort(ostokset);
	return ostokset;
    }

    public String toString() {
	return "Ostoskori[" + asiakas() + " , " + ostokset.size() + " tuotetta]";
    }

}
      

Osatehtävä 2.4: Pääohjelmaluokka Verkkokauppa

Tehtävänanto

Laadi pääohjelmaluokka, jolla voit testata verkkokauppaa.

Vastaus

Oheisessa pääohjelmassa luodaan Valikoima ja lisätään sinne kirjoja ja CD:itä. Sitten luodaan Ostoskori ja lisätään sinne tuotteita. Osa tuotteista lisätään useita kertoja. Lopuksi ostoskorin sisältö tulostetaan.

import java.util.Iterator;

public class Verkkokauppa {
    public static void main(String[] args) {
	Valikoima v = new Valikoima();
	v.lisääTuote(new Kirja("0001",
			       "The Java Language Specification Second Edition",
			       new String[]{"Gosling, James", "Joy, Bill",
						"Steele, Guy", "Bracha, Gilad"},
			       "0-201-31008-2"));
	v.lisääTuote(new CD("0020", "Hard Rock Cafe", "The Doors"));
	v.lisääTuote(new CD("0037", "Wired", "Jeff Beck"));
	v.lisääTuote(new CD("0127", "Humppakäräjät", "Eläkeläiset"));
	v.lisääTuote(new Kirja("0005",
			       "Change. Principles of Problem Formation and Problem Resolution",
			       new String[]{"Watzlawick, Paul",
						"Weakland, John",
						"Fisch, Richard"},
			       "0-393-01104-6"));
	v.lisääTuote(new CD("0120", "Pancha Nadai Pallavi", "Shankar"));
	v.lisääTuote(new Kirja("0011",
			       "Women, Fire, and Dangerous Things: What Categories Reveal About the Mind",
			       new String[]{"Lakoff, George"},
			       "0-226-46804-6"));
	System.out.println(v);
	Ostoskori o = new Ostoskori("Arska Asiakas");
	System.out.println(o);
	o.lisääTuote(v.haeTuote("0120"));
	o.lisääTuote(v.haeTuote("0011"));
	o.lisääTuote(v.haeTuote("0011"));
	o.lisääTuote(v.haeTuote("0127"));
	o.lisääTuote(v.haeTuote("0127"));
	o.lisääTuote(v.haeTuote("0037"));
	o.lisääTuote(v.haeTuote("0005"));
	System.out.println(o + ": ");
	Iterator it = o.tuotteet().iterator();
	while (it.hasNext()) {
	    Tuote t = (Tuote)it.next();
	    System.out.println(t.kuvaus());
	}
    }
}
      

Esimerkkiajo

Valikoima[3 kirjaa, 4 CD:tä]
Ostoskori[Arska Asiakas , 0 tuotetta]
Ostoskori[Arska Asiakas , 7 tuotetta]: 
Fisch, Richard, Watzlawick, Paul, Weakland, John: Change. Principles of Problem Formation and Problem Resolution. ISBN: 0-393-01104-6
Lakoff, George: Women, Fire, and Dangerous Things: What Categories Reveal About the Mind. ISBN: 0-226-46804-6
Lakoff, George: Women, Fire, and Dangerous Things: What Categories Reveal About the Mind. ISBN: 0-226-46804-6
Jeff Beck: Wired
Shankar: Pancha Nadai Pallavi
Eläkeläiset: Humppakäräjät
Eläkeläiset: Humppakäräjät
      

Studio1
Last modified: Thu Nov 15 19:57:50 EET 2001