Her ligger løsningsforslaget til eksamen 2021. Vi vil senere legge til ofte forekommende feil og misforståelser i kombinasjon med kildekoden .

På gitlab finner dere full kode til alle deler i oppgaven.


Oppgaven handler om å holde oversikt over et pågaende vaksinestudie.

public class VaccineTrialVolunteer {

	public VaccineTrialVolunteer(String id, boolean placebo) {
		...
	}

	public String getId() {
		...
	}

	/* Whether the volunteer was given a placebo or the actual vaccine */
	public boolean isPlacebo() {
		...
	}

	/* Whether the volunteer got sick during the trial period, 
	 * the default value for this should be false */
	public boolean gotSick() {
		...
	}

	/*
	 * Updates whether the participant got sick during the trial period
	 */
	public void setGotSick(boolean gotSick) {
		...
	}

}


public class VaccineTrial {

	// Add any needed fields here

	/**
	 * Adds a new VaccineTrialVolunteer to the trial
	 * 
	 * @param id      The id of the volunteer
	 * 
	 * @param placebo Whether the volunteer was given a placebo, or the actual
	 *                vaccine
	 */

	public void addVolunteer(String id, boolean placebo) {
		// TODO
	}

	/**
	 * Returns whether the vaccine's effectiveness rate is higher than the provided
	 * limit. The effectiveness of the vaccine is calculated as follows: 
	 * 
	 * 1- (number of people that received the vaccine and got sick/
	 *         number of people that got sick)
	 * 
	 * If there is no sick people, the vaccine is not effective
	 * 
	 * @param limit A limit to compare against
	 * 
	 * @throws IllegalArgumentException If limit is not between (including) 0 and 1.
	 * 
	 * @return Whether the vaccine effectiveness rate is higher than the limit
	 */
	public boolean isMoreEffectiveThanLimit(double limit) {
		...

	}

	/**
	 * Updates the sick state of a VaccineTrialVolunteer
	 * 
	 * @param id The id of the volunteer to set sick.
	 * @throws IllegalArgumentException if there is no volunteer with the given id
	 */
	public void setSick(String id) {
		...
	}

	/**
	 * Get's the volunteer with the given ID
	 * 
	 * @param id The id of the volunteer to set sick.
	 * 
	 * @return The vaccine trial volunteer with the given ID. If the ID is not valid
	 *         for any volunteer, return null
	 */
	public VaccineTrialVolunteer getVolunteer(String id) {
		...
	}

}

Oppgave a) Utfyll klassen VaccineTrialVolunteer og alle metodene i denne klassen. Legg til nødvendige felt. VaccineTrialVolunteer skal ha følgende metoder:

  • VaccineTrialVolunteer(String id, boolean placebo) - Oppretter en ny frivillig deltaker, med den gitte ID-en og hvorvidt deltakeren fikk placebo eller faktiske vaksinen.
  • getId() - Henter ut ID-en til deltakeren.
  • isPlacebo() - Returnere hvorvidt deltakeren fikk placebo eller vaksine.
  • gotSick() - Returnere hvorvidt deltakeren ble syk i løpet av studien.
  • setGotSick(boolean gotSick) - Oppdaterer om deltakeren ble syk i løpet av studien.
public class VaccineTrialVolunteer {

	private final String id;
	private final boolean placebo; 
	private boolean gotSick;
	
	public VaccineTrialVolunteer(String id, boolean placebo) {
		this.id = id;
		this.placebo = placebo;
	}

	public String getId() {
		return this.id;
	}

	/* Whether the volunteer was given a placebo or the actual vaccine */
	public boolean isPlacebo() {
		return this.placebo;
	}

	/* Whether the volunteer got sick during the trial period, 
	 * the default value for this should be false */
	public boolean gotSick() {
		return this.gotSick;
	}

	/*
	 * Updates whether the participant got sick during the trial period
	 */
	public void setGotSick(boolean gotSick) {
		this.gotSick = gotSick;
	}

}

Oppgave b)

 Fyll ut klassen VaccineTrial, og alle metodene i denne klassen. Legg til egne nødvendige felt. VaccineTrial skal ha følgende metoder:

  • addVolunteer(String id, boolean placebo) - Legger til en deltaker i studien.
  • isMoreEffectiveThanLimit(double limit) - Hvorvidt vaksinen var mer effektiv enn den oppgitte grensen.
  • setSick(String id) - Oppdaterer deltakeren med den gitte ID-en til å ha blitt syk i løpet av studien.
  • VaccineTrialVolunteer getVolunteer(String id) - Returnerer deltakeren med den gitte ID-en.
import java.util.ArrayList;
import java.util.Collection;

public class VaccineTrial {

	// Add any needed fields here
	private Collection<VaccineTrialVolunteer> volunteers = new ArrayList<>();

	/**
	 * Adds a new VaccineTrialVolunteer to the trial
	 * 
	 * @param id      The id of the volunteer
	 * 
	 * @param placebo Whether the volunteer was given a placebo, or the actual
	 *                vaccine
	 */
	public void addVolunteer(String id, boolean placebo) {
		this.volunteers.add(new VaccineTrialVolunteer(id, placebo));

	}

	/**
	 * Returns whether the vaccine's effectiveness rate is higher than the provided
	 * limit. The effectiveness of the vaccine is calculated as follows: 
	 * 
	 * 1- (number of people that received the vaccine and got sick/
	 *         number of people that got sick)
	 * 
	 * If there is no sick people, the vaccine is not effective
	 * 
	 * @param limit A limit to compare against
	 * 
	 * @throws IllegalArgumentException If limit is not between (including) 0 and 1.
	 * 
	 * @return Whether the vaccine effectiveness rate is higher than the limit
	 */
	public boolean isMoreEffectiveThanLimit(double limit) {
		if (limit < 0 || limit > 1) {
			throw new IllegalArgumentException("Invalid limit");
		}
		double numberOfSick = 0;
		double numberOfSickWithVaccine = 0;
		for (VaccineTrialVolunteer volunteer: volunteers) {
			if (volunteer.gotSick()) {
				numberOfSick++;
				if (!volunteer.isPlacebo()) {
					numberOfSickWithVaccine++;
				}
			}
		}
		double ratio  = 1.0-(numberOfSickWithVaccine/numberOfSick);
		return ratio > limit;
	}

	/**
	 * Updates the sick state of a VaccineTrialVolunteer
	 * 
	 * @param id The id of the volunteer to set sick.
	 * @throws IllegalArgumentException if there is no volunteer with the given id
	 */
	public void setSick(String id) {
		VaccineTrialVolunteer volunteer = this.getVolunteer(id);
		if (volunteer == null) {
			throw new IllegalArgumentException("invalid ID");
		}
		volunteer.setGotSick(true);
	}

	/**
	 * Get's the volunteer with the given ID
	 * 
	 * @param id The id of the volunteer to set sick.
	 * 
	 * @return The vaccine trial volunteer with the given ID. If the ID is not valid
	 *         for any volunteer, return null
	 */
	public VaccineTrialVolunteer getVolunteer(String id) {
		for (VaccineTrialVolunteer volunteer: volunteers) {
			if (volunteer.getId().equals(id)) {
				return volunteer;
			}
		}
		return null;
	}
}


Fyll inn set og get-metodene i Person-klassen. Du skal gjøre dette uten å endre kode i Address-klassen.

// DO NOT MODIFY THIS CLASS
public class Address {

	private String streetName;
	private int streetNumber;

	public Address(String streetName, int streetNumber) {
		this.streetName = streetName;
		this.streetNumber = streetNumber;
	}

	public String getStreetName() {
		return streetName;
	}

	public int getStreetNumber() {
		return streetNumber;
	}

}


public class Person {

	// No other fields should be added to this class
	private Address address;

	
	// You do not need to consider the edge case of passing null into the constructor here
	public Person(Address address) {
		this.address = address;
	}
	
	/**
	 * 
	 * @return the street name of this person
	 */
	public String getStreetName() {
		...
	}

	/**
	 * Updates the street name of this person
	 * 
	 * @param streetName The street name to update
	 */
	public void setStreetName(String streetName) {
		...
	}
	
	
	public int getStreetNumber() {
		...
	}

	/**
	 * Updates the street number of this person
	 * 
	 * @param streetNumber A positive integer.
	 * 
	 * @throws IllegalArgumentException If number is not larger than 0.
	 */
	public void setStreetNumber(int streetNumber) {
		...
	}
}

public class Person {

	// No other fields should be added to this class
	private Address address;

	
	// You do not need to consider the edge case of passing null into the constructor here
	public Person(Address address) {
		this.address = address;
	}
	
	/**
	 * 
	 * @return the street name of this person
	 */
	public String getStreetName() {
		return this.address.getStreetName();
	}

	/**
	 * Updates the street name of this person
	 * 
	 * @param streetName The street name to update
	 */
	public void setStreetName(String streetName) {
		this.address = new Address(streetName, this.address.getStreetNumber());
	}
	
	
	public int getStreetNumber() {
		return this.address.getStreetNumber();
	}

	/**
	 * Updates the street number of this person
	 * 
	 * @param streetNumber A positive integer.
	 * 
	 * @throws IllegalArgumentException If number is not larger than 0.
	 */
	public void setStreetNumber(int streetNumber) {
		if (streetNumber <= 0) {
			throw new IllegalArgumentException();
		}
		this.address = new Address(this.address.getStreetName(), streetNumber);

	}
}

Følgende vedlagte klasser/interfaces brukes, men skal ikke endres i denne oppgaven. Du trenger ikke forstå hvordan metodene er implementert, bare benytte deg direkte av de.

  • SomeServiceImpl - Implementasjon av SomeService.
  • SomeService - Grensesnitt som implementers i både SomeServiceImpl og LoggingSomeService.
  • Logger - En hjelpeklasse for å logge resultater.

Du skal fylle ut LoggingSomeService og metodene/konstruktør i denne klassen. LoggingSomeService skal delegere videre til en delegat, som skal utføre arbeidet, og deretter logge resultatet før det returneres. Følgende metoder skal implementeres:

  • LoggingSomeService(SomeService delegate, Logger logger) - Oppretter et objekt av LoggingSomeService med en delegat og en logger.
  • getAMagicString() - Returnerer en magisk String. Det er den delegertes oppgave å hente ut Stringen, og den skal logges før det returneres.
  • getAMagicNumber() - Returnerer et magisk tall. Det er den delegertes oppgave å hente ut tallet, og det skal logges før det returneres.
public interface SomeService {

	public String getAMagicString();

	public int getAMagicNumber();
}


public class Logger {

	// This is only for testing
	Collection<String> hasLogged = new ArrayList<>();

	public void log(String log) {
		System.out.println(log);
		hasLogged.add(log);
	}
}
public class SomeServiceImpl implements SomeService {

	@Override
	public String getAMagicString() {
		return "magic";
	}

	@Override
	public int getAMagicNumber() {
		return 42;
	}

}


public class LoggingSomeService implements SomeService {

	// Add needed fields here

	/*
	 * Creates a LoggingSomeService object with the given delegate and logger
	 */
	public LoggingSomeService(SomeService delegate, Logger logger) {
		...
	}

	@Override
	/**
	 * Delegates the job of calculating a magic string to the delegate, and logs the
	 * result before returning it
	 * 
	 * @return A string
	 */
	public String getAMagicString() {
		...
	}

	/**
	 * Delegates the job of calculating a magic number to the delegate, and logs the
	 * result before returning it
	 * 
	 * @return An integer
	 */
	@Override
	public int getAMagicNumber() {
		...
	}
}


public interface SomeService {

	public String getAMagicString();

	public int getAMagicNumber();
}

import java.util.ArrayList;
import java.util.Collection;

public class Logger {

	// This is only for testing
	Collection<String> hasLogged = new ArrayList<>();

	public void log(String log) {
		System.out.println(log);
		hasLogged.add(log);
	}
}
public class SomeServiceImpl implements SomeService {

	@Override
	public String getAMagicString() {
		return "magic";
	}

	@Override
	public int getAMagicNumber() {
		return 42;
	}

}
public class LoggingSomeService implements SomeService {

	// Add needed fields here
	private SomeService delegate;
	private Logger logger;
	/*
	 * Creates a LoggingSomeService object with the given delegate and logger
	 */
	public LoggingSomeService(SomeService delegate, Logger logger) {
		this.delegate = delegate;
		this.logger = logger;
	
	}

	@Override
	/**
	 * Delegates the job of calculating a magic string to the delegate, and logs the
	 * result before returning it
	 * 
	 * @return A string
	 */
	public String getAMagicString() {
		String magic = delegate.getAMagicString();
		logger.log(magic);
		return magic;
	}

	/**
	 * Delegates the job of calculating a magic number to the delegate, and logs the
	 * result before returning it
	 * 
	 * @return An integer
	 */
	@Override
	public int getAMagicNumber() {
		int magicNumber = delegate.getAMagicNumber();
		logger.log(Integer.toString(magicNumber));
		return magicNumber;
	}
}


Fyll inn vedlagte AthleteComparators og de to metodene der. Du skal ta utgangspunkt i, men ikke trenge å endre Athlete og Medal som ligger vedlagt.

Det er tillatt å legge til metoder i disse klassene dersom du mener det er hjelpemetoder som vil være til hjelp. Ingen ekstra metoder du legger til bør endre tilstanden til objektene.

Følgende metoder skal implementeres:

  • getSimpleComparator() - Returner en comparator som skal brukes til å sammenlikne Athletes basert på navnet deres alfabetisk. Det vil si at Ane kommer før Berit, som igjen kommer før Daniel.
  • getAdvancedComparator Returner en comparator som skal brukes til å sammenlikne Athletes basert på antall medaljer de har. En atlet som har to gullmedaljer, vil komme før en atlet som har en gullmedalje og en sølvmedalje. Dersom de har likt antall medaljer av en type går man videre til neste medaljetype, og hvis de har likt antall medaljer av alle typer skal man sammenlikne basert på navnet som i getSimpleComparator.
import java.util.ArrayList;
import java.util.List;

public class Athlete {
	
	private List<Medal> medals = new ArrayList<Medal>();
	private String country;
	private String name;

	public Athlete(String country, String name, List<Medal> medals) {
		this.name = name;
		this.country = country;
		this.medals = new ArrayList<>(medals);
	}

	public List<Medal> getMedals() {
		return new ArrayList<>(medals);
	}

	public String getCountry() {
		return country;
	}

	public String getName() {
		return name;
	}

}
import java.util.Arrays;
import java.util.List;

public class Medal {
	
	private String metal;
	public static List<String> validMetals = Arrays.asList("Gold", "Silver", "Bronze");

	public Medal(String metal) {
		if (!validMetals.contains(metal)) {
			throw new IllegalArgumentException("Invalid medal");
		}
		this.metal = metal;
	}

	public String getMetal() {
		return metal;
	}
}


public class AthleteComparators {

	/**
	 * @return a comparator that compares athletes based on their name. Using this
	 *          comparator, Ane should come before Berit
	 */
	public static Comparator<Athlete> getSimpleComparator() {
		...
	}

	/**
	 * @return A comparator that compares athletes based on the number of medals of
	 *          different valour. The comparator will be used for sorting athletes
	 *          based on putting the athlete with the highest number of medals of the best valour
	 *          first.
	 * 
	 *          If one athlete has more "Gold" medals than the other athlete it
	 *          should come before that one. If they have equal number of "Gold"
	 *          medals they should be compared on the number of "Silver" medals, and
	 *          if that is equal on the number of "Bronze" medals. If they have the
	 *          same number of medals of all valour, they should be compared based
	 *          on the name similar to getSimpleComparator
	 *          
	 *          The spelling and order of the medals can be seen in the list validMetals in the Medal class. 
	 */
	public static Comparator<Athlete> getAdvancedComparator() {
		...
	}
}

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class AthleteComparators {

	/**
	 * @return a comparator that compares athletes based on their name. Using this
	 *          comparator, Ane should come before Berit
	 */
	public static Comparator<Athlete> getSimpleComparator() {
		return new Comparator<Athlete>() {
			public int compare(Athlete a, Athlete b) {
				return a.getName().compareTo(b.getName());
			}
		};
	}

	/**
	 * @return A comparator that compares athletes based on the number of medals of
	 *          different valour. The comparator will be used for sorting athletes
	 *          based on putting the athlete with the highest number of medals of the best valour
	 *          first.
	 * 
	 *          If one athlete has more "Gold" medals than the other athlete it
	 *          should come before that one. If they have equal number of "Gold"
	 *          medals they should be compared on the number of "Silver" medals, and
	 *          if that is equal on the number of "Bronze" medals. If they have the
	 *          same number of medals of all valour, they should be compared based
	 *          on the name similar to getSimpleComparator
	 *          
	 *          The spelling and order of the medals can be seen in the list validMetals in the Medal class. 
	 */
	public static Comparator<Athlete> getAdvancedComparator() {
		return new Comparator<Athlete>() {
			public int compare(Athlete a, Athlete b) {

				for (String metal : Medal.validMetals) {
					int numberOfMedalsA = (int) a.getMedals().stream().filter(medal -> medal.getMetal().equals(metal))
							.count();
					int numberOfMedalsB = (int) b.getMedals().stream().filter(medal -> medal.getMetal().equals(metal))
							.count();
					if (numberOfMedalsA != numberOfMedalsB) {
						return numberOfMedalsB - numberOfMedalsA;
					}
				}
				return a.getName().compareTo(b.getName());
			}
		};
	}
}



Ta utgangspunkt i LoyaltyUser-klassen. LoyaltyUser er en klasse som implementerer en bruker som kan samle statuspoeng, og som kan gå opp og ned i status basert på dette.

Lojalitetsprogrammet samarbeider med andre og det er derfor ønskelig at andre kan lytte på statusen til en bruker. Grensesnittet for dette er definert i StatusListener.

Oppgave A) Fyll ut nødvendige metoder og felt for å støtte lytting i LoyaltyUser klassen, for å gjøre det mulig å lytte på endring i statusen til et brukernavn.

Viktig:

  • En lytter vil kun være interessert i en status, og dersom lytteren registreres på nytt er det en ny status den skal lytte på.
  • Selv om lytteren kun er interessert i en status, vil den være interessert i både når brukeren oppnår denne statusen og når den mister den.

Følgende metoder skal endres/implementeres:

  • checkForStatusUpgrade() - sjekker om brukeren kvalifiserer seg til en endring i statusnivå. Dersom statusen endres bør den si ifra til alle lytterne.
  • addListener(StatusListener listener, String status) - Registrerer en lytter som lytter på status.
  • removeListener(StatusListener listener) - fjerner lytteren.
  • fireStatusChanged(String oldStatus, String newStatus) - Sier ifra til alle lytterne som lytter på enten oldStatus eller newStatus om at statusen er endret.
public interface StatusListener {
	
	/**
	 * 
	 * @param username The username of the user
	 * @param oldStatus The old status of the user
	 * @param newStatus The new status of the user
	 */
	public void statusChanged(String username, String oldStatus, String newStatus);

}



import java.util.Arrays;
import java.util.List;

public class LoyaltyUser {
	private String username;
	private int points;
	private String status;
	public static List<String> validStatuses = Arrays.asList("Basic", "Gold", "Silver", "Platinum");
	// TODO - Add any extra needed fields here

	public LoyaltyUser(String username) {
		this.username = username;
		this.status = "Basic";
	}

	public String getUsername() {
		return username;
	}

	public int getPoints() {
		return points;
	}

	public String getStatus() {
		return status;
	}

	/**
	 * Adds point to this user
	 * @param points the points to add. Can also be a negative number
	 */
	public void addPoints(int points) {
		this.points += points;
		this.checkForStatusUpgrade();
	}

	/**
	 * Checks whether the user qualifies for a status upgrade/downgrade.
	 * 
	 * TODO: If the user qualifies for a new status all observers interested in the new or old
	 * status should be notified
	 */
	public void checkForStatusUpgrade() {
		if (this.points <= 1000) {
			this.status = "Basic";
		}
		if (this.points > 1000) {
			this.status = "Silver";
		}
		if (this.points > 5000) {
			this.status = "Gold";
		}
		if (this.points > 10000) {
			this.status = "Platinum";
		}
	}

	/**
	 * Adds a listener that listens on when this specific status is obtained or
	 * lost. If the user has been previously added, the old status should be
	 * overridden and the listener should listen on the new status
	 * 
	 * @param listener The listener that will observe
	 * 
	 * @param status   The status the listener will listen to
	 * 
	 * @throws IllegalArgumentException If the status is not valid
	 */
	public void addListener(StatusListener listener, String status) {
		...

	}

	/**
	 * Remove the listener
	 * 
	 * @param listener The listener to remove
	 */
	public void removeListener(StatusListener listener) {
		...
	}

	/**
	 * Updates all listeners that were interested in either the old or the new
	 * status that the status of the user has changed. Observers should only be
	 * notified if oldStatus and newStatus is different
	 * 
	 * @param oldStatus The old status of the user
	 * 
	 * @param newStatus The new status of the user
	 */
	private void fireStatusChanged(String oldStatus, String newStatus) {
		...
	}
}


/* RentalCar listeners listens to changes in Status for all userNames.*/
public class RentalCarListener implements StatusListener {

	// TODO - Add any needed fields here

	@Override
	/**
	 * Method that should be called when a given userName has updated its status.
	 */
	public void statusChanged(String username, String oldStatus, String newStatus) {
		/// TODO
	}

	/**
	 * Get's the discount of a user. Should be a 100 if the user currently has Gold
	 * status, otherwise should be 0.
	 * 
	 * @param username The username of the user
	 * 
	 * @return The discount the user qualifies for.
	 */
	public int getDiscount(String username) {
		// TODO
		return 0;
	}
}
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class LoyaltyUser {
	private String username;
	private int points;
	private String status;
	public static List<String> validStatuses = Arrays.asList("Basic", "Gold", "Silver", "Platinum");
	// TODO - Add any extra needed fields here
	private Map<StatusListener, String> statusListeners = new HashMap<>();

	public LoyaltyUser(String username) {
		this.username = username;
		this.status = "Basic";
	}

	public String getUsername() {
		return username;
	}

	public int getPoints() {
		return points;
	}

	public String getStatus() {
		return status;
	}

	/**
	 * Adds point to this user
	 * @param points the points to add. Can also be a negative number
	 */
	public void addPoints(int points) {
		this.points += points;
		this.checkForStatusUpgrade();
	}

	/**
	 * Checks whether the user qualifies for a status upgrade/downgrade.
	 * 
	 * TODO: If the user qualifies for a new status all observers interested in the new or old
	 * status should be notified
	 */
	public void checkForStatusUpgrade() {
		String oldStatus = this.status;

		if (this.points <= 1000) {
			this.status = "Basic";
		}
		if (this.points > 1000) {
			this.status = "Silver";
		}
		if (this.points > 5000) {
			this.status = "Gold";
		}
		if (this.points > 10000) {
			this.status = "Platinum";
		}
		if (oldStatus != this.status) {
			this.fireStatusChanged(oldStatus, this.status);
		}
	}
	
	private void checkIsValidStatus(String status) {
		if (!validStatuses.contains(status)) {
			throw new IllegalArgumentException("Invalid status");
		}
	}

	/**
	 * Adds a listener that listens on when this specific status is obtained or
	 * lost. If the user has been previously added, the old status should be
	 * overridden and the listener should listen on the new status
	 * 
	 * @param listener The listener that will observe
	 * 
	 * @param status   The status the listener will listen to
	 * 
	 * @throws IllegalArgumentException If the status is not valid
	 */
	public void addListener(StatusListener listener, String status) {
		checkIsValidStatus(status);
		this.statusListeners.put(listener, status);

	}

	/**
	 * Remove the listener
	 * 
	 * @param listener The listener to remove
	 */
	public void removeListener(StatusListener listener) {
		this.statusListeners.remove(listener);

	}

	/**
	 * Updates all listeners that were interested in either the old or the new
	 * status that the status of the user has changed. Observers should only be
	 * notified if oldStatus and newStatus is different
	 * 
	 * @param oldStatus The old status of the user
	 * 
	 * @param newStatus The new status of the user
	 */
	private void fireStatusChanged(String oldStatus, String newStatus) {
		for (StatusListener listener: this.statusListeners.keySet()) {
			String status = this.statusListeners.get(listener);
			if (oldStatus.equals(status) || newStatus.equals(status)) {
				listener.statusChanged(this.username, oldStatus, newStatus);
			}
		}
	}
}

Oppgave b) Implementer RentalCarListener. RentalCarListener lytter på endringer i status til LoyaltyUser i LoyaltyUser for å kunne gi gullmedlemmer rabatt.

  • statusChanged(String username, String oldStatus, String newStatus) - Registerer endringen i status for et gitt brukernavn.
  • getDiscount(String username) Returnerer rabatten til et brukernavn. Skal være 100 hvis brukeren innehar gullnivå, ellers 0.
import java.util.HashMap;
import java.util.Map;

/* RentalCar listeners listens to changes in Status for all userNames.*/
public class RentalCarListener implements StatusListener {

	// TODO - Add any needed fields here
	// Many will probably have solved this using a list instead, which is also a good solution
	private Map<String, Integer> rebates = new HashMap<>();
	private final String GOLD_STATUS = "Gold";
	@Override
	/**
	 * Method that should be called when a given userName has updated its status.
	 */
	public void statusChanged(String username, String oldStatus, String newStatus) {
		if (newStatus.equals(GOLD_STATUS)) {
			rebates.put(username, 100);
		}
		else {
			rebates.remove(username);
		}
	}

	/**
	 * Get's the discount of a user. Should be a 100 if the user currently has Gold
	 * status, otherwise should be 0.
	 * 
	 * @param username The username of the user
	 * 
	 * @return The discount the user qualifies for.
	 */
	public int getDiscount(String username) {
		return rebates.getOrDefault(username, 0);

	}
}

Ta utgangspunkt i den abstrakte klassen LoyaltyAward og klassen CarRentalAwards. Disse klassene implementerer metoder for å tildele poeng til en bruker ut ifra hvilket bilmerke den har leid.

Under implementasjonen av disse klassene har det kommet inn to feil som eksponeres ved kjøring av main-metoden i CarRentalAwards.

Rett opp feilene (dette vil innebære både at koden ikke krasjer og at riktig logikk utføres).

Følgende metoder finnes i LoyaltyAward:

  • LoyaltyAward(String awardName) - Oppretter et LoyaltyAward objekt med det gitte navnet.
  • setAwardName(String awardName) - Oppdaterer navnet på prisen.
  • awardPoints(int points, LoyaltyUser loyaltyUser) Gir antall poeng til den gitte brukeren.

Følgende metoder finnes i CarRentalAwards:

  • CarRentalAwards(String awardName Oppretter et CarRentalAwards objekt med det gitte navnet.
  • setAwardName(String awardName) - Oppdaterer navnet på prisen dersom det er gyldig.
  • awardPoints(int carBrand, LoyaltyUser loyaltyUser) - Gir et visst antall poeng til den gitte brukeren. Antall poeng er beregnet ut ifra hvilket bilmerke brukeren har leid.
public abstract class LoyaltyAward {

	private String awardName;

	public LoyaltyAward(String awardName) {
		this.setAwardName(awardName);
	}

	/**
	 * Updates the name of the award
	 * @param awardName the new award name
	 */
	public void setAwardName(String awardName) {
		this.awardName = awardName;
	}

	/**
	 * Adds the points to the given loyalty user.
	 *
	 * @param points      The points to award to the user
	 * @param loyaltyUser The user that rented the car
	 */

	public void awardPoints(int points, LoyaltyUser loyaltyUser) {
		loyaltyUser.addPoints(points);
	}
}


import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class CarRentalAwards extends LoyaltyAward {

	private Map<Integer, Integer> carBrandToPoints = Map.of(1, 1, 2, 10, 3, 100, 4, 200, 5, 500);
	private List<String> validNames = Arrays.asList("CarRentalAgency1", "CarRentalAgency2");

	public CarRentalAwards(String awardName) {
		super(awardName);
	}

	@Override
	/**
	 * Updates the award name
	 * @param: awardName The name of the award
	 * 
	 * @throws IllegalArgumentException If the award name is not part of the valid
	 *                                  names
	 */
	public void setAwardName(String awardName) {
		if (!validNames.contains(awardName)) {
			throw new IllegalArgumentException("Invalid award name");
		}
		super.setAwardName(awardName);
	}

	/**
	 * Updates the status of the given LoyaltyUser with points based on the map
	 * above. The map means that carBrand 1 will award 1 points, carBrand 2 will
	 * award 10 points etc
	 * 
	 * @param carBrand:    The brand of the car the user has rented. If the brand
	 *                     does not exist 0 points should be awarded
	 * 
	 * @param loyaltyUser: The user that rented the car
	 * 
	 * 
	 */
	public void awardPoints(int carBrand, LoyaltyUser loyaltyUser) {
		Integer points = carBrandToPoints.get(carBrand);
		if (points != null) {
			awardPoints(points, loyaltyUser);
		}
	}

	public static void main(String[] args) {
		LoyaltyUser user = new LoyaltyUser("Name");
		// What goes wrong here
		LoyaltyAward award = new CarRentalAwards("CarRentalAgency1");
		// What goes wrong here
		award.awardPoints(1, user);
		System.out.println(user.getPoints());
	}

}

Mangler

Ta utgangspunkt i den vedlagte Course-klassem. Denne klassen trengs ikke å endres for oppgaven. Course-klassen har oversikt over:

  • Et navn.
  • Gjennomsnittskarakter.
  • Andre emner som er forkunnskapskrav til dette emnet.

Du skal fylle ut UniversityHandbook -klassen sine metoder for å kunne lese emner fra fil og holde oversikt over disse emenene. Det vil bli gitt poeng etter følgende oppnåelse, så dersom du ikke får til hele oppgaven vil du få uttelling for delvis løsning.

  1. Lese inn emners navn og gjennomsnittskarakter fra fil.
  2. Støtte å legge til forkunnskapskrav om emner som har vært tidligere i filen.
  3. Støtte å legge til forkunnskapskrav om emner som kommer senere i filen.

Følgende metoder skal fullføres/implementeres:

  • readFromInputStream(InputStream stream) - Leser inn emner fra en gitt inputStream. (Se eksempelfilen i src/main/resources/del7_og_8/courses.txt for hvordan disse kan se ut.)
  • getCourse(String courseName) - Returnerer emnet med det gitte navnet.
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class Course {
	// The name of the course
	private String courseName;
	// A list of course prerequisites for this course. This means that all the courses in this list should be taken before this one. 
	private List<Course> prerequisites = new ArrayList<>();
	// The average grade of the course
	private double averageGrade;

	public Course(String courseName, double averageGrade) {
		this(courseName);
		this.averageGrade = averageGrade;
	}

	public Course(String courseName) {
		this.courseName = courseName;
	}
	
	public String getCourseName() {
		return courseName;
	}

	public void setAverageGrade(double averageGrade) {
		this.averageGrade = averageGrade;
	}
	
	public double getAverageGrade() {
		return averageGrade;
	}
	
	/**
	 * Adds a new prerequisite to this course
	 * @param course The course to add
	 */
	public void addPrequisite(Course course) {
		this.prerequisites.add(course);
	}
	
	/**
	 * 
	 * @return A copy of the list of prerequisites
	 */
	public Collection<Course> getPrerequisites() {
		return new ArrayList<>(prerequisites);
	}
	
	public String toString() {
		return this.courseName;
	}

}


import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class UniversityHandbook {

	private List<Course> courses = new ArrayList<>();

	/**
	 * Reads all the courses from a given input stream. The courses are on this
	 * form: courseName, averageGrade, prerequisite 1, prerequisite 2,
	 * prerequisite 3....
	 * 
	 * See courses.txt in src/main/resources/del7_og_8 for an example file.
	 * 
	 * Calling this method should remove any existing courses from the handbook.
	 * 
	 * A given course can have anything from 0 to unlimited number of prerequisites.
	 * The courses do not necessary come in order. Meaning that a course may appear
	 * in the prerequisite list as a never before seen course. The method should read
	 * in all courses, and set the courseName, averageGrade and prerequisites of all
	 * courses and add the courses to the courses field of this class.
	 * 
	 * A skeleton code to read from file is provided to you but feel free to write
	 * your own code for this.
	 * 
	 * You can assume that all lines from the file will be on the correct format.
	 * 
	 * @param stream InputStream containing the course data
	 */
	public void readFromInputStream(InputStream stream) {
		try (Scanner scanner = new Scanner(stream)) {
			while (scanner.hasNextLine()) {
				String line = scanner.nextLine();
				String[] details = line.split(",");
				// TODO - Continue implementation here
			}
		}
	}

	/**
	 * Gets the course with the courseName
	 * 
	 * @param courseName The name of the course
	 * 
	 * @return The course with the given name
	 */
	public Course getCourse(String courseName) {
		...
	}
}

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Scanner;

public class UniversityHandbook {

	private Collection<Course> courses = new ArrayList<>();

	/**
	 * Reads all the courses from a given input stream. The courses are on this
	 * form: courseName, averageGrade, prerequisite 1, prerequisite 2,
	 * prerequisite 3....
	 * 
	 * See courses.txt in src/main/resources/del7_og_8 for an example file.
	 * 
	 * Calling this method should remove any existing courses from the handbook.
	 * 
	 * A given course can have anything from 0 to unlimited number of prerequisites.
	 * The courses do not necessary come in order. Meaning that a course may appear
	 * in the prerequisite list as a never before seen course. The method should read
	 * in all courses, and set the courseName, averageGrade and prerequisites of all
	 * courses and add the courses to the courses field of this class.
	 * 
	 * A skeleton code to read from file is provided to you but feel free to write
	 * your own code for this.
	 * 
	 * You can assume that all lines from the file will be on the correct format.
	 * 
	 * @param stream InputStream containing the course data
	 */
	public void readFromInputStream(InputStream stream) {
		this.courses = new ArrayList<>();
		try (Scanner scanner = new Scanner(stream)) {
			while (scanner.hasNextLine()) {
				String line = scanner.nextLine();
				String[] details = line.split(",");
				String courseName = details[0];
				double averageGrade = Double.parseDouble(details[1]);
				Course course = this.findOrCreateCourse(courseName);
				course.setAverageGrade(averageGrade);
				
				for (int i=2;i<details.length; i++) {
					String prequesite = details[i];
					Course coursePrequesite = findOrCreateCourse(prequesite);
					course.addPrequisite(coursePrequesite);
				}
				
			}
		}
	}


	/**
	 * Get's the course with the courseName
	 * 
	 * @param courseName The name of the course
	 * 
	 * @return The course with the given name
	 */
	public Course getCourse(String courseName) {
		for(Course course: courses) {
			if (course.getCourseName().equals(courseName)) {
				return course;
			}
		}
		return null;
	}

	private Course findOrCreateCourse(String name) {
		Course course = getCourse(name);
		if (course != null) {
			return course;
		}
		course = new Course(name);
		this.courses.add(course);
		return course;
	}
}

Fyll ut UniversityHandbookUtils sine metoder for operasjoner på en liste med Course-objekter.

Følgende metoder skal implementeres:

  • getCoursesWithPredicate(Collection courses, Predicate p) - Returnerer alle emner i samlingen som tilfredstiller predikatet.
  • getNonPrequisiteCourses(Collection courses) - Returnerer alle emner i samlingen som ikke har noen forkunnskapskrav.
  • containsImpossibleCourse(Collection courses) - Returnerer hvorvidt samlingen av emner inneholder et emne som er umulig. Et umulig emne er definert som et emne X som har et forkunnskaps krav, som har emnet X som forkunnskapskrav.

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.List;
    import java.util.function.Predicate;
    
    public class UniversityHandbookUtils {
    
    	/**
    	 * Get all courses that matches the given predicate
    	 * 
    	 * @param courses The list of courses to check for
    	 * @param p       The predicate that should be matched on
    	 *
    	 * @return A collection of courses that satisfy the predicate.
    	 */
    	public static Collection<Course> getCoursesWithPredicate(Collection<Course> courses, Predicate<Course> p) {
    		...
    	}
    
    	/**
    	 * Get all courses that does not have any prerequisites
    	 * 
    	 * @param courses The list of courses to check for
    	 * @return A collection of course without any prerequisites
    	 */
    	public static Collection<Course> getNonPrequisiteCourses(Collection<Course> courses) {
    		...
    
    	}
    	
    	/**
    	 * Returns whether the handbook contains an impossible course. A course is
    	 * deemed impossible if any of the prerequisite of the course has the current
    	 * course as a prerequisite. Only direct dependencies need to be checked. You
    	 * do not need to worry about transitive dependencies. That means if TDT4100 has
    	 * a dependency on TDT4110 and TDT4110 has a dependency on TDT4100 it is impossible.
    	 * 
    	 * A transitive dependency that does not need to be checked is if TDT4100 has a
    	 * dependency on TDT4110, TDT4110 has dependency on TDT4200 and TDT4200 has a
    	 * dependency on TDT4100.
    	 * 
    	 * @param courses The list of courses to check for
    	 * @return whether the courses contains an impossible course
    	 */
    	public static boolean containsImpossibleCourse(Collection<Course> courses) {
    		...
    	}
    }
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.List;
    import java.util.function.Predicate;
    import java.util.stream.Collectors;
    
    public class UniversityHandbookUtils {
    
    	/**
    	 * Get all courses that matches the given predicate
    	 * 
    	 * @param courses The list of courses to check for
    	 * @param p       The predicate that should be matched on
    	 *
    	 * @return A collection of courses that satisfy the predicate.
    	 */
    	public static Collection<Course> getCoursesWithPredicate(Collection<Course> courses, Predicate<Course> p) {
    		return courses.stream().filter(p).collect(Collectors.toList());
    
    	}
    
    	/**
    	 * Get all courses that does not have any prerequisites
    	 * 
    	 * @param courses The list of courses to check for
    	 * @return A collection of course without any prerequisites
    	 */
    	public static Collection<Course> getNonPrequisiteCourses(Collection<Course> courses) {
    		return courses.stream().filter(course -> course.getPrerequisites().size() == 0).collect(Collectors.toList());
    	}
    	
    	/**
    	 * Returns whether the handbook contains an impossible course. A course is
    	 * deemed impossible if any of the prerequisite of the course has the current
    	 * course as a prerequisite. Only direct dependencies need to be checked. You
    	 * do not need to worry about transitive dependencies. That means if TDT4100 has
    	 * a dependency on TDT4110 and TDT4110 has a dependency on TDT4100 it is impossible.
    	 * 
    	 * A transitive dependency that does not need to be checked is if TDT4100 has a
    	 * dependency on TDT4110, TDT4110 has dependency on TDT4200 and TDT4200 has a
    	 * dependency on TDT4100.
    	 * 
    	 * @param courses The list of courses to check for
    	 * @return whether the courses contains an impossible course
    	 */
    	public static boolean containsImpossibleCourse(Collection<Course> courses) {
    		return courses.stream().anyMatch(course -> course.getPrerequisites().stream().anyMatch(prerequesite -> prerequesite.getPrerequisites().contains(course)));
    
    	}
    }