Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

 I denne oppgaven skal dere skrive kode for 3 klasser relatert til desimaltall med benevning:

  • Unit, som er en klasse for enhet/benevning,

Strukturen av kode og metoder det skal jobbes med på denne eksamen, er samlet i vedlegget. Oppførselen er spesifisert i strukturerte kommentarer over klasser og metoder. Det blir henvist til vedlegget i hele oppgavesettet.

Expand
titleDel 1 – Unit-klassen (35%)
 Oppgave a)
Unit-klassen er utformet slik at instanser ikke skal kunne endres etter at de er opprettet. Hva er generelle fordeler og ulemper med klasser som gir ikke-modifiserbare (immutable) instanser?
Expand
titleLF

Klassen blir enklere, og minsker bl.a. behovet for validering. Instanser kan brukes av flere deler av et program, uten risiko for at en del endrer på dem og ødelegger for en annen del. Ulempen er at en må lage nye instanser hvis de må rettes på, istedenfor å endre dem direkte.

Oppgave b)
Skriv ferdig de tre konstruktørene og definer nødvendige felt. Hva er hensikten med bruken av throws-nøkkelordet, slik det er brukt her? Er det strengt tatt nødvendig og evt. hvorfor/hvorfor ikke?
Expand
titleLF
Code Block
private final String symbol;
public Unit(String symbol) throws IllegalArgumentException {
	this(symbol, null, 1.0, 0.0);
}
private final Unit base;
private final double factor, offset;
public Unit(String symbol, Unit base, double factor, double offset) throws IllegalArgumentException {
	for (int i = 0; i < symbol.length(); i++) {
		char c = symbol.charAt(i);
		if (! Character.isAlphabetic(c)) {
			throw new IllegalArgumentException(c + " is an illegal symbol character");
		}
	}
	this.symbol = symbol;
	this.base = base;
	this.factor = factor;
	this.offset = offset;
}
public Unit(String symbol, Unit base, double factor) throws IllegalArgumentException {
	this(symbol, base, factor, 0.0);
}

throws-deklarasjonen forteller leseren av koden at konstruktørene kan utløse unntak. Siden unntakene er en subklasse av RuntimeException og dermed ikke checked, så er det ikke nødvendige.

Oppgave c)
Hva er hensikten med å definere en toString()-metode?
Expand
titleLF

toString()-metoden brukes implisitt når Java lager String-objekter av instanser ifm. bruk av + og IO og sikrer at tilstanden til instanser blir presentert på en nyttig måte.

Oppgave d)

Nederst i klassen defineres en del meter-relaterte Unit-instanser (m, km og dm og cm). Tegn objektdiagram som illustrerer objektstrukturen som disse instansene utgjør.

Expand
titleLF

Her er verdiene til feltene og kjeden av base-linker vesentlig.

Oppgave e)
Metoden findCommonBaseUnit er sentral i konvertering av verdier mellom ulike enheter. Den skal virke slik at dm.findCommonBaseUnit(km) returnerer m-instansen. Skriv ferdig metoden.
Expand
titleLF
Code Block
themeEclipse
public Unit findCommonBaseUnit(Unit other) {
	Unit unit1 = this;
	while (unit1 != null) {
		Unit unit2 = other;
		while (unit2 != null) {
			if (unit2 == unit1) {
				return unit1;
			}
			unit2 = unit2.base;
		}
		unit1 = unit1.base;
	}
	return null;
}
Oppgave f)
convert-metoden er ferdigskrevet og bruker de to hjelpemetodene convertToBase og convertFromBase. De to hjelpemetodene kaller også seg selv. Forklar hvilke kall som gjøres til disse (inkludert de til seg selv) og hvilke argumenter de får og verdier de returnerer, i løpet av utførelsen av dm.convert(2.0, km).
Expand
titleLF
...
Oppgave g)
valueOf-metoden ”oversetter” fra et enhetssymbol til en Unit-instans, litt på samme måten som Double.valueOf lager en Double-verdi fra en String. Men merk at Unit.valueOf ikke skal lage nye instanser, men returnere en av de predefinerte! Skriv ferdig valueOf-metoden.
Expand
titleLF
Code Block
themeEclipse
public static Unit valueOf(String symbol) {
	for (Unit unit : ALL_UNITS) {
		if (symbol.equals(unit.symbol)) {
			return unit;
		}
	}
	return null;
}
Expand
titleDel 2 –Value-klassen (25%)
 Oppgave a)

 Hva er hensikten med get-metoder? Fullfør konstruktøren, get-metodene og deklarer nødvendige felt.

Expand
titleLF

 get-metoder gir tilgang til tilstanden uten å ”avsløre” hvilke felt som brukes for å representere tilstanden.

Code Block
themeEclipse
private final Unit unit;
private final double value;
public Value(Unit unit, double value) {
	this.unit = unit;
	this.value = value;
}
public Unit getUnit() {
	return unit;
}
public double getValue() {
	return value;
}


Oppgave b)
valueOf-metoden ”oversetter” fra en String til en Value-instans, litt på samme måten som Double.valueOf lager en Double-verdi fra en String. Skriv ferdig valueOf-metoden.
Expand
titleLF
Code Block
themeEclipse
public static Value valueOf(String s) {
	int pos = s.length();
	while (Character.isAlphabetic(s.charAt(pos - 1))) {
		pos--;
	}
	return new Value(Unit.valueOf(s.substring(pos)), Double.valueOf(s.substring(0, pos)));
}
Oppgave c)
Skriv ferdig add, compute og mult-metodene.
Expand
titleLF
Code Block
themeEclipse
public Value add(Value other) {
	Unit base = this.unit.findCommonBaseUnit(other.unit);
	double sum = this.unit.convert(value, base) + other.unit.convert(other.value, base);
	return new Value(base, sum);
}
public Value compute(BinaryOperator<Double> op, double other) {
	double result = op.apply(this.value, other);
	return new Value(this.unit, result);
}	
public Value mult(double other) {
	return compute((v1,  v2) -> v1 * v2, other);
}
Oppgave d)
Value-klassen implementerer Comparable<Value>. Hvorfor er det nyttig? Skriv ferdig compare-metodene.
Expand
titleLF

Ved å implementere Comparable-grensesnittet så kan Value-objekter sorteres vha. Java sine innebygde sort-metoder.

Code Block
themeEclipse
public int compareTo(Value other) {
	Unit base = this.unit.findCommonBaseUnit(other.unit);
	if (base == null) {
		throw new IllegalArgumentException("Cannot compare " + this + " with " + other);
	}
	double d1 = this.unit.convert(value, base), d2 = other.unit.convert(other.value, base);
	if (d1 < d2) {
		return -1;
	} else if (d1 > d2) {
		return 1;
	} else {
		return 0;
	}
}
Expand
titleDel 3 – Values-grensesnittet og ValueSeries-klassen (25%)
Oppgave a)

Values-grensesnittet utvider Iterable<Double>. Hvorfor er det nyttig/praktisk?

Expand
titleLF
 
Oppgave b)

Values-grensesnittet er ment å støtte observerbarhet og observert-observatør-teknikken, men deklarasjonen av metodene for lytterhåndtering er erstattet av ”…”. Skriv de to deklarasjonene.

Expand
titleLF
Code Block
themeEclipse
public void addValuesListener(ValuesListener listener);
public void removeValuesListener(ValuesListener listener); 
Oppgave c)

Skriv ferdig konstruktøren og de to appendValue-metodene i ValueSeries-klassen. Definer nødvendige felt.

Expand
titleLF
Code Block
private final Unit unit;
private Collection<Double> values  = new ArrayList<Double>();
public ValueSeries(Unit unit) {
	this.unit = unit;
}
public void appendValue(double value) {
	values.add(value);
	fireValuesChanged();
}
public void appendValue(Value value) {
	appendValue(value.getUnit().convert(value.getValue(), getUnit()));
}
Oppgave d)
Implementer metodene i ValueSeries-klassen, som er nødvendige for å gjøre klassen komplett.
Expand
titleLF
Code Block
themeEclipse
@Override
public int size() {
	return values.size();
}
@Override
public double average() {
	double sum = 0.0;
	for (double value : values) {
		sum += value;
	}
	return sum / values.size();
}
@Override
public Unit getUnit() {
	return unit;
}
@Override
public Iterator<Double> iterator() {
	return values.iterator();
}
//
@Override
public Values add(Values other) {
	Unit base = this.unit.findCommonBaseUnit(other.getUnit());
	ValueSeries result = new ValueSeries(base);
	Iterator<Double> otherDoubles = other.iterator();
	for (double value : values) {
		double otherDouble = otherDoubles.next();
		double sum = this.unit.convert(value, base) + other.getUnit().convert(otherDouble, base);
		result.appendValue(sum);
	}
	return result;
}
// ValuesListener support
private Collection<ValuesListener> listeners = new ArrayList<ValuesListener>();
@Override
public void addValuesListener(ValuesListener listener) {
	listeners.add(listener);
}
@Override
public void removeValuesListener(ValuesListener listener) {
	listeners.remove(listener);
}
protected void fireValuesChanged() {
	for (ValuesListener listener : listeners) {
		listener.valuesChanged(this);
	}
}
Expand
titleDel 4 – Testing (10%)

I denne delen skal du skrive testkode for Value- og ValueSeries-klassene. Hensikten er å vise at du behersker testmetodikken, og du kan, men trenger ikke bruke JUnit-rammeverket.  

Oppgave a)

Skriv testkode for Value sin valueOf-metode.

Expand
titleLF
Code Block
themeEclipse
public void testValueOf() {
	Value value = Value.valueOf("2.0m");
	assertEquals(Unit.valueOf("m"), value.getUnit());
	assertEquals(2.0, value.getValue());
}


Oppgave b)