- Created by Unknown User (mattiamn), last modified on 29.01.2022
Her ligger løsningsforslaget til kontinuasjonseksamen 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.
package del1; public class VoterCounter { // Add any needed fields here public static final String TIE_RESULT = "TIE"; /** * Register a candidate to the poll * * @param candidate the new candidate to add */ public void addCandidate(String candidate) { // TODO } /** * Vote on a given candidate * * @param candidate the candidate to vote on * * @throws IllegalArgumentException if the candidate is not registered */ public void castVote(String candidate) { // TODO } /** * Prints all the results in an arbitrary order. The results should be on the * format {candidate name}-{number of votes for the candidate} with each * candidate on a new line * * Example output with two candidates, "Candidate1" with 7 votes, and * "Candidate2" with 6 votes * * Candidate1-7 * Candidate2-6 */ public String getFormattedResults() { // TODO return null; } /** * Returns the number of votes a candidate has received * * @param candidate the candidate to get number of votes for * @return the number of votes the candidate has received. Returns null if the * candidate is not registered */ public Integer getNumberOfVotes(String candidate) { // TODO return 0; } /** * * @return the name of the candidate who won the election. If two or more * candidates got the same number of maximum votes, return the * TIE_RESULT field. Return null if there are no candidates. */ public String getWinner() { // TODO return null; } public static void main(String[] args) { String candidate1 = "CANDIDATE1"; String candidate2 = "CANDIDATE2"; VoterCounter counter = new VoterCounter(); counter.addCandidate(candidate1); counter.addCandidate(candidate2); // Should print 0 System.out.println(counter.getNumberOfVotes(candidate1)); counter.castVote(candidate1); // Should print 1; System.out.println(counter.getNumberOfVotes(candidate1)); // Should print CANDIDATE 1 System.out.println(counter.getWinner()); counter.castVote(candidate2); // Should print TIE System.out.println(counter.getWinner()); } }
Utfyll klassen VoterCounter, og alle metodene i denne klassen. Legg til egne nødvendige felt. VoterCounter skal ha oversikt over kandidater som stiller til valg, og antall stemmer de har fått.
- addCandidate(String candidateName) - Registrerer en kandidat en kan stemme på
- castVote(String candidate) - Gir en stemme til kandidaten
- getFormattedResults() - Returnerer antall stemmer hver kandidat har fått
- getVotes(String candidate) - Returnerer antall stemmer en kandidat har fått
- getWinner() - Returnerer kandidaten som fikk flest stemmer, eventuelt om det ble uavgjort
package del1; import java.util.HashMap; import java.util.Map; public class VoterCounter { private Map<String, Integer> votes = new HashMap<>(); public static final String TIE_RESULT = "TIE"; /** * Register a candidate to the poll * * @param candidate the new candidate to add */ public void addCandidate(String candidate) { votes.put(candidate, 0); } /** * Vote on a given candidate * * @param candidate the candidate to vote on * * @throws IllegalArgumentException if the candidate is not registered */ public void castVote(String candidate) { if (!this.votes.containsKey(candidate)) { throw new IllegalArgumentException(); } votes.replace(candidate, votes.get(candidate) + 1); } /** * Prints all the results in an arbitrary order. The results should be on the * format {candidate name}-{number of votes for the candidate} with each * candidate on a new line */ public String getFormattedResults() { String s = ""; for (String candidate : votes.keySet()) { s += (candidate + "-" + votes.get(candidate)) + "\n"; } return s; } /** * Get's the number of votes a candidate has received * * @param candidate the candidate to get number of votes for * @return the number of votes the candidate has received. null if the candidate * is not registered */ public Integer getNumberOfVotes(String candidate) { return votes.getOrDefault(candidate, null); } /** * * @return the name of the candidate who won the election. If two or more * candidates got the same number of maximum votes, return the * TIE_RESULT field. Return null if there is no candidates. */ public String getWinner() { int maxValue = 0; String winner = null; for (String candidate : votes.keySet()) { if (votes.get(candidate) > maxValue) { winner = candidate; maxValue = votes.get(candidate); } } for (String candidate : votes.keySet()) { if (votes.get(candidate) == maxValue && !winner.equals(candidate)) { return TIE_RESULT; } } return winner; } public static void main(String[] args) { String candidate1 = "CANDIDATE1"; String candidate2 = "CANDIDATE2"; VoterCounter counter = new VoterCounter(); counter.addCandidate(candidate1); counter.addCandidate(candidate2); // Should print 0 System.out.println(counter.getNumberOfVotes(candidate1)); counter.castVote(candidate1); // Should print 1; System.out.println(counter.getNumberOfVotes(candidate1)); // Should print CANDIDATE 1 System.out.println(counter.getWinner()); counter.castVote(candidate2); // Should print TIE System.out.println(counter.getWinner()); } }
Komplementer AppController og UI.fxml så de fungerer sammen etter hensikten. Dette kan innebære å knytte opp felt/metoder i både Controller og .fxml-filen.
package del2; import javafx.fxml.FXML; import javafx.scene.control.TextArea; public class AppController { // TODO - Add any needed fields here @FXML public TextArea output; public static String logInSuccess = "Gratulerer du har logget inn!"; public static String logInFailed = "Feil brukernavn eller passord"; /** * TODO - what should be the name of this method? Uncomment this part of the * code and put it inside the correct function public void { String brukernavn; * // Extract username from FXML here String passord; // Extract password from * FXML here * * if (brukernavn.equals("admin") && passord.equals("admin")) { * output.setText(logInSuccess); } else { output.setText(logInFailed); } } */ } package del2; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.stage.Stage; public class App extends Application { @Override public void start(final Stage primaryStage) throws Exception { primaryStage.setTitle("My app"); primaryStage.setScene(new Scene(FXMLLoader.load(App.class.getResource("Ui.fxml")))); primaryStage.show(); } public static void main(String[] args) { App.launch(args); } } //Code for the fxml-file <?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.Button?> <?import javafx.scene.control.Label?> <?import javafx.scene.control.TextArea?> <?import javafx.scene.control.TextField?> <?import javafx.scene.layout.AnchorPane?> <AnchorPane prefHeight="400.0" prefWidth="695.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="del2.AppController"> <children> <Label layoutX="112.0" layoutY="111.0" text="Brukernavn" /> <Label layoutX="272.0" layoutY="111.0" text="Passord" /> <TextField fx:id="username" layoutX="53.0" layoutY="128.0" /> <TextField fx:id="password" layoutX="249.0" layoutY="128.0" /> <TextArea fx:id="output" layoutX="114.0" layoutY="178.0" prefHeight="200.0" prefWidth="200.0" /> <Button layoutX="464.0" layoutY="128.0" mnemonicParsing="false" onAction="#onLogIn" text="Logg inn" /> </children> </AnchorPane>
package del2; import javafx.fxml.FXML; import javafx.scene.control.TextArea; import javafx.scene.control.TextField; public class AppController { //TODO - Add any needed fields here @FXML public TextArea output; @FXML private TextField username, password; public static String logInSuccess = "Gratulerer du har logget inn!"; public static String logInFailed = "Feil brukernavn eller passord"; @FXML public void onLogIn() { String brukernavn = username.getText();// Extract username from FXML here String passord = password.getText(); // Extract password from FXML here if (brukernavn.equals("admin") && passord.equals("admin")) { output.setText(logInSuccess); } else { output.setText(logInFailed); } } } //Code for the fxml-file <?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.Button?> <?import javafx.scene.control.Label?> <?import javafx.scene.control.TextArea?> <?import javafx.scene.control.TextField?> <?import javafx.scene.layout.AnchorPane?> <AnchorPane prefHeight="400.0" prefWidth="695.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="kortforklart.AppController"> <children> <Label layoutX="112.0" layoutY="111.0" text="Brukernavn" /> <Label layoutX="272.0" layoutY="111.0" text="Passord" /> <TextField fx:id="username" layoutX="53.0" layoutY="128.0" /> <TextField fx:id="password" layoutX="249.0" layoutY="128.0" /> <TextArea fx:id="output" layoutX="114.0" layoutY="178.0" prefHeight="200.0" prefWidth="200.0" /> <Button layoutX="464.0" layoutY="128.0" mnemonicParsing="false" onAction="#onLogIn" text="Logg inn" /> </children> </AnchorPane>
Følgende vedlagte klasser/interfaces brukes, men skal ikke endres i denne klassen. Du trenger ikke forstå hvordan metodene er implementert, bare benytte deg direkte av dem.
- CalculationsImpl - Implementasjon av Calculations
- Calculations - Grensesnitt som implementeres i både CalculationsImpl og CachingCalculations
Du skal fylle ut CachingCalculations og metodene/konstruktør i denne klassen.
CachingCalculations skal delegere til en delegate, som skal utføre arbeidet og deretter memoisere resultatet. memoisere betyr her at hvis metoden får et argument den tidligere har sett skal den heller returnere det tidligere kalkulerte resultatet, enn å be delegate gjøre beregningen på nytt. Denne teknikken brukes gjerne når beregninger er kostbare å utføre.
- CachingCalculations(Calculations delegate) - Oppretter et CachingCalculations objekt
- getCalculation1(int number) - Gjør beregning 1
- getCalculation2(int number) - Gjør beregning 2.
package del3; public class CalculationsImpl implements Calculations { @Override public int getCalculation1(int number) { return (int) Math.sqrt(number); } @Override public int getCalculation2(int number) { return number * number; } } package del3; public interface Calculations { public int getCalculation1(int number); public int getCalculation2(int number); } package del3; public class CachingCalculations implements Calculations { public CachingCalculations(Calculations delegate) { // TODO } @Override /** * Delegates the job of calculating the square root to the delegate If the * argument has been previously seen, the delegate should not be used and a * local cached version of the result should be returned * * @returns the calculation applied to the argument */ public int getCalculation1(int number) { // TODO return 0; } @Override /** * Delegates the job of calculating the square to the delegate If the argument * has been previously seen, the delegate should not be used and a local cached * version of the result should be returned * * @returns the calculation applied to the argument */ public int getCalculation2(int number) { // TODO return 0; } public static void main(String[] args) { CachingCalculations calc = new CachingCalculations(new CalculationsImpl()); // Should print 81 System.out.println(calc.getCalculation2(9)); // Should print 81 again, should not use the delegate System.out.println(calc.getCalculation2(9)); // Should print 3 System.out.println(calc.getCalculation1(9)); } }
package del3; import java.util.HashMap; import java.util.Map; public class CachingCalculations implements Calculations { private Calculations delegate; private Map<Integer, Integer> cache1 = new HashMap<>(); private Map<Integer, Integer> cache2 = new HashMap<>(); public CachingCalculations(Calculations delegate) { this.delegate = delegate; } @Override /** * Delegates the job of calculating the square root to the delegate If the * argument has been previously seen, the delegate should not be used and a * local cached version of the result should be returned * * @returns the square root of the argument */ public int getCalculation1(int number) { if (cache1.containsKey(number)) { return cache1.get(number); } int result = delegate.getCalculation1(number); cache1.put(number, result); return result; } @Override /** * Delegates the job of calculating the square to the delegate If the argument * has been previously seen, the delegate should not be used and a local cached * version of the result should be returned * * @returns the square of the argument */ public int getCalculation2(int number) { if (cache2.containsKey(number)) { return cache2.get(number); } int result = delegate.getCalculation2(number); cache2.put(number, result); return result; } public static void main(String[] args) { CachingCalculations calc = new CachingCalculations(new CalculationsImpl()); // Should print 81 System.out.println(calc.getCalculation2(9)); // Should print 81 again, should not use the delegate System.out.println(calc.getCalculation2(9)); // Should print 3 System.out.println(calc.getCalculation1(9)); } }
Oppgave a) Objektstrukturer (12 %)
Fyll inn vedlagte Temperature. Temperature har oversikt over en temperatur som enten er i Fahrenheit eller i Celsius.
Temperature har følgende metoder
- Temperature(double degrees, char scale) - Initialiserer et Temperature-objekt med en skala (Fahrenheit/Celsius) og et antall grader
- getScale() - Returnerer om temperaturen er i Fahrenheit eller Celsius.
- getDegrees() - Returnerer temperaturen i antall grader.
- toOther() - Gjør om dette temperatur-objektet til den andre skalaen og returnerer det.
- inOther() - Lager et nytt temperatur-objekt i den den andre skalaen og returnerer det.
- lower(double amount) - Senker temperaturen med et antall grader.
package del4; public class Temperature { // Add any needed fields /** * * @param degrees an arbitrary number * @param scale a character declaring the scale * * @throws IllegalArgumentException if scale is not 'C' or 'F' */ public Temperature(double degrees, char scale) { // TODO } /** * * @return The current scale */ public char getScale() { // TODO return '0'; } /** * * @return the current degree of this object */ public double getDegrees() { // TODO return 0; } /** * Converts this temperature object to be the opposite scale of what it * currently is * * @return this temperature object, converted with value in Celsius if the scale * of this temperature object is Fahrenheit, and value in Fahrenheit if * this the scale of this temperature object is Celsius */ public Temperature toOther() { // TODO return null; } /** * Creates a new temperature object with values in the other scale of this * temperature object * * @return a new Temperature object, with value in Celsius if the scale of this * temperature object is Fahrenheit, and value in Fahrenheit if the * scale of this temperature object is Celsius */ public Temperature inOther() { // TODO return null; } /** * Lowers the temperature * * @param amount the amount to lower by */ public void lower(double amount) { // TODO } /** * * @param celsius * @return the temperature in Fahrenheit */ public static double convertCelsisusToFahrenheit(double celsius) { return (celsius * 1.8 + 32.0); } /** * * @param fahrenheit * @return the temperature in Celsius */ public static double convertFahrenheitToCelsius(double fahrenheit) { return (fahrenheit - 32.0) / 1.8; } public static void main(String[] args) { Temperature t = new Temperature(20, 'C'); // Should print 20 System.out.println(t.getDegrees()); t.lower(10); // Should now print 10 System.out.println(t.getDegrees()); t.toOther(); // Should now print 50 System.out.println(t.getDegrees()); t.toOther(); Temperature t2 = t.inOther(); // Should be 50; System.out.println(t2.getDegrees()); // Should be 10 System.out.println(t.getDegrees()); } }
package del4; public class Temperature { private char scale; // Only valid values are C or F private double degree; /** * * @param degrees an arbitrary number * @param scale a character declaring the scale * * @throws IllegalArgumentException if scale is not 'C' or 'F' */ public Temperature(double degrees, char scale) { this.degree = degrees; if (scale != 'C' && scale != 'F') { throw new IllegalArgumentException(); } this.scale = scale; } /** * * @return The current scale */ public char getScale() { return scale; } /** * * @return the current degree of this object */ public double getDegrees() { return degree; } /** * Converts this temperature object to be the opposite scale of what it * currently is * * @return this temperature object, converted with value in Celsius if the value * of this temperature object is Fahrenheit, and value in Fahrenheit if * this temperature object is Celsius */ public Temperature toOther() { if (this.scale == 'C') { this.scale = 'F'; this.degree = convertCelsisusToFahrenheit(this.degree); } else { this.scale = 'C'; this.degree = convertFahrenheitToCelsius(this.degree); } return this; } /** * Creates a new temperature object with values in the other scale of this * temperature object. * * @return a new Temperature object, with value in Celsius if the value of this * temperature object is Fahrenheit, and value in Fahrenheit if this * temperature object is Celsius */ public Temperature inOther() { if (this.scale == 'C') { return new Temperature(convertCelsisusToFahrenheit(this.degree), 'F'); } else { return new Temperature(convertFahrenheitToCelsius(this.degree), 'C'); } } /** * Lowers the temperature * @param amount the amount to lower by */ public void lower(double amount) { this.degree -= amount; } /** * * @param celsius * @return the temperature in Fahrenheit */ public static double convertCelsisusToFahrenheit(double celsius) { return (celsius * 1.8 + 32.0); } /** * * @param fahrenheit * @return the temperature in Celsius */ public static double convertFahrenheitToCelsius(double fahrenheit) { return (fahrenheit - 32.0) / 1.8; } public static void main(String[] args) { Temperature t = new Temperature(20, 'C'); // Should print 20 System.out.println(t.getDegrees()); t.lower(10); // Should now print 10 System.out.println(t.getDegrees()); t.toOther(); // Should now print 50 System.out.println(t.getDegrees()); t.toOther(); Temperature t2 = t.inOther(); // Should be 50; System.out.println(t2.getDegrees()); // Should be 10 System.out.println(t.getDegrees()); } }
Oppgave b) Delegering (8%)
Fyll inn DelegatingTemperature. DelegatingTemperature skal delegere til et underliggende Temperature-objekt og ha metodene beskrevet under. Du kan gå ut ifra at alle metodene til delegaten fungerer slik de skal.
- DelegatingTemperature(Temperature delegate, char scale) - Oppretter et DelegatingTemperature-objekt med en skala (Fahrenheit/Celsisus) og et antall grader som er representert i delegaten.
- getScale() - Returnerer om temperaturen er i Fahrenheit eller Celsius.
- getDegrees() - Returnerer temperaturen i antall grader.
- toOther() - Gjør om dette temperatur-objektet til den andre skalaen og returnerer det.
- inOther() - Lager et nytt temperatur-objekt i den den andre skalaen og returnerer det.
package del4; public class DelegatingTemperature { // Add any needed fields /** * * @param delegate - the Temperature to get degree from * @param scale a character declaring the scale of this temperature object * * @throws IllegalArgumentException if scale is not 'C' or 'F' */ public DelegatingTemperature(Temperature delegate, char scale) { // TODO } /** * * @return The current scale */ public char getScale() { // TODO return '0'; } /** * * @return the current degree from the delegate, converted to the correct scale */ public double getDegrees() { // TODO return 0; } /** * * @return this temperature object, with scale converted to Celsius if the * current scale of this delegatingTemperature object is in Fahrenheit, * and value in Fahrenheit if this delegatingTemperature object is in * Celsius */ public DelegatingTemperature toOther() { // TODO return null; } /** * * @return a new DelegatingTemperature object, with the same delegate, with * scale converted to Celsius if the current scale of this * delegatingTemperature object is Fahrenheit, and value in Fahrenheit * if this delegatingTemperature object is Celsius */ public DelegatingTemperature inOther() { // TODO return null; } public static void main(String[] args) { Temperature t = new Temperature(10, 'C'); DelegatingTemperature dt = new DelegatingTemperature(t, 'F'); // Should now print 10 System.out.println(t.getDegrees()); // Should now print 50 System.out.println(dt.getDegrees()); dt.toOther(); // Should now print 10 System.out.println(dt.getDegrees()); // Should now print 10 System.out.println(t.getDegrees()); } }
package del4; public class DelegatingTemperature { // Add any needed fields private Temperature delegate; private char scale; /** * * @param delegate - the Temperature to get degree from * @param scale a character declaring the scale of this temperature object * * @throws IllegalArgumentException if scale is not 'C' or 'F' */ public DelegatingTemperature(Temperature delegate, char scale) { this.delegate = delegate; this.setScale(scale); } /** * * @return The current scale */ public char getScale() { return this.scale; } private void setScale(char scale) { if (scale != 'F' && scale != 'C') { throw new IllegalArgumentException() ; } this.scale = scale; } /** * * @return the current degree from the delegate, converted to the correct scale */ public double getDegrees() { if (this.scale == this.delegate.getScale()) { return this.delegate.getDegrees(); } return this.delegate.inOther().getDegrees(); } /** * * @return this temperature object, with scale converted to Celsius if the * current scale of this delegatingTemperature object is in Fahrenheit, and * value in Fahrenheit if this delegatingTemperature object is in Celsius */ public DelegatingTemperature toOther() { this.scale = this.scale == 'C' ? 'F' : 'C'; return this; } /** * * @return a new DelegatingTemperature object, with the same delegate, with * scale converted to Celsius if the current scale of this * delegatingTemperature object is Fahrenheit, and value in Fahrenheit * if this delegatingTemperature object is Celsius */ public DelegatingTemperature inOther() { return new DelegatingTemperature(this.delegate, this.scale == 'C' ? 'F' : 'C'); } public static void main(String[] args) { Temperature t = new Temperature(10, 'C'); DelegatingTemperature dt = new DelegatingTemperature(t, 'F'); // Should now print 10 System.out.println(t.getDegrees()); // Should now print 50 System.out.println(dt.getDegrees()); dt.toOther(); // Should now print 10 System.out.println(dt.getDegrees()); // Should now print 10 System.out.println(t.getDegrees()); } }
Del 5, 6, 7 og 8 bygger på hverandre, men kan løses uavhengig av hverandre selv om main-metodene da ikke nødvendigvis vil gi rett resultat. Det vil ofte kreve at du har forstått hva metodene skal gjøre, men du kan gå ut ifra at implementasjonen er rett selv om du ikke har fått til en metode.
Ta utgangspunkt i Property-klassen. Property er en klasse som implementerer en eiendom som kan motta bud for å bli kjøpt.
Interessenter i eiendommen er interessert i å kunne lytte på nye bud Bid på eiendommen.
Fyll ut nødvendige metoder og felt for å støtte lytting i Property klassen, for å gjøre det mulig og lytte på nye bud på eiendommen. Følgende metoder skal implementeres:
- setIsSold() - Markerer eiendommen som solgt.
- addListener(BidListener listener) - Registrerer en lytter
- emoveListener(BidListener listener) - Fjerner en lytter
- bidReceived(String bidder, int bid) - Oppretter et nytt Bid og registrerer dette, og sier ifra registrerte lyttere avhengig om budet er det høyeste til nå eller ikke.
- addListenerForHighestBids(BidListener listener) - Registrerer en lytter som kun skal lytte på bud som er det høyeste budet til nå
- notifyListeners(Bid bid) - Sier ifra til alle lytterne om det nye budet
- getHighestBid - Returnererer det høyeste budet
package del5_8; public class Property { // Add any needed fields here /** * * @param name the name of the property to be sold * @param price the listing price of the property */ public Property(String name, int price) { // TODO } /** * * @return the name of the property */ public String getName() { // TODO return null; } /** * * @return the price of the property */ public int getPrice() { // TODO return 0; } /** * * @return whether the property is sold, default value is false */ public boolean isSold() { // TODO return false; } /** * Sets the property as sold * * @throws IllegalStateException if no bids have been received */ public void setIsSold() { // TODO } /** * * @return the number of bids received on this property */ public int getNumberOfBids() { // TODO return 0; } /** * * @param listener register listener to be notified of any bids to this property */ public void addListenerForAllBids(BidListener listener) { // TODO } /** * * @param listener register listener to be notified of only bids that are new * highest bids You do not need to handle the case where a * listener gets registered both for highest bid and for all * bids */ public void addListenerForHighestBids(BidListener listener) { // TODO } /** * * @param listener removes listener from this property, registered with any of * the above methods */ public void removeListener(BidListener listener) { // TODO } /** * Creates a new bid object and notifies all listeners that a bid has been given * * @param bidder the name of the bidder * @param bid the amount of the bid * * @throws IllegalStateException - if the property is already sold */ public void bidReceived(String bidder, int bid) { // TODO } /** * Notifies listeners that a bid has been received. There are currently no * listeners implemented in the main method, but this is used for test purposes * by us after the exam. * * This is package private for testing purposes * * @param bid the most recent bid */ void notifyListeners(Bid bid) { // TODO } /** * * @return the current highest bid. If the property has no bids, return 0 */ public int getHighestBid() { // TODO return 0; } public static void main(String[] args) { Property p = new Property("name", 1000); p.bidReceived("BIDDER", 500); // 500 System.out.println(p.getHighestBid()); p.bidReceived("BIDDER2", 1100); // 1100 System.out.println(p.getHighestBid()); // false System.out.println(p.isSold()); p.setIsSold(); // true System.out.println(p.isSold()); } } package del5_8; public class Bid { private int bid; private Property property; private String bidder; public Bid(String bidder, Property property, int bid) { this.bid = bid; this.property = property; this.bidder = bidder; } public int getBid() { return bid; } public Property getProperty() { return property; } public String getBidder() { return bidder; } public boolean equals(Object otherBid) { if (otherBid instanceof Bid) { Bid bid2 = (Bid) otherBid; boolean isBidEqual = this.bid == bid2.bid; boolean isPropertyEqual = this.property.getName().equals(bid2.property.getName()); boolean isBidderEqual = this.bidder.equals(bid2.bidder); boolean isEqual = isBidEqual && isPropertyEqual && isBidderEqual; return isEqual; } return false; } public String toString() { return this.property.getName() + bid; } }
package del5_8; import java.util.ArrayList; import java.util.List; public class Property { private String name; private List<BidListener> interests = new ArrayList<>(); private List<BidListener> highestBidInterests = new ArrayList<>(); private List<Bid> bids = new ArrayList<>(); private int price; private boolean isSold = false; /** * * @param name the name of the property to be sold * @param price the listing price of the property */ public Property(String name, int price) { this.name = name; this.price = price; } /** * * @return the name of the property */ public String getName() { return this.name; } /** * * @return the price of the property */ public int getPrice() { return this.price; } /** * * @return whether the property is sold, default value is false */ public boolean isSold() { return this.isSold; } /** * * @return the number of bids received on this property */ public int getNumberOfBids() { return this.bids.size(); } /** * Sets the property as sold * * @throws IllegalStateException if no bids have been received */ public void setIsSold() { // TODO if (this.bids.size() == 0) { throw new IllegalStateException("no bids received"); } this.isSold = true; } /** * * @param listener register listener to be notified of any bids to this property */ public void addListenerForAllBids(BidListener listener) { // TODO this.interests.add(listener); } /** * * @param listener register listener to be notified of only bids that are higher * than the current highest bid */ public void addListenerForHighestBids(BidListener listener) { this.highestBidInterests.add(listener); } /** * * @param listener removes listener from this property */ public void removeListener(BidListener listener) { // TODO this.interests.remove(listener); } /** * Creates a new bid object and notifies all listeners that a bid has been given * * @param bidder the name of the bidder * @param bid the amount of the bid * * @throws IllegalStateException - if the property is already sold. */ public void bidReceived(String bidder, int bid) { // TODO if (this.isSold()) { throw new IllegalStateException(); } Bid b = new Bid(bidder, this, bid); this.notifyListeners(b); this.bids.add(b); } /** * Notifies listener that a bid has been received * * @param bid the most recent bid */ public void notifyListeners(Bid bid) { this.interests.forEach(listener -> listener.propertyBid(bid)); if (bid.getBid() > this.getHighestBid()) { this.highestBidInterests.forEach(listener -> listener.propertyBid(bid)); } } /** * * @return the current highest bid. If the property has no bids, return 0 */ public int getHighestBid() { return this.bids.stream().mapToInt(b -> b.getBid()).max().orElse(0); } public static void main(String[] args) { Property p = new Property("name", 1000); p.bidReceived("BIDDER", 500); // 500 System.out.println(p.getHighestBid()); p.bidReceived("BIDDER2", 1100); // 1100 System.out.println(p.getHighestBid()); // false System.out.println(p.isSold()); p.setIsSold(); // true System.out.println(p.isSold()); } }
BusinessProperty BusinessProperty arver fra Property men har noe ulik oppførsel.
BusinessProperty tar imot bud på samme måte, men skal registreres som solgt med en gang et bud som er over prisen på eiendommen er satt.
Gjør nødvendige endringer for å få til dette i BusinessProperty.
package del5_8; public class BusinessProperty extends Property { /** * BusinessProperty should implement the following extensions from Property. As * soon as a bid is received that is equal to or higher than the price, the * property should be marked as sold */ public BusinessProperty(String name, int price) { super(name, price); } public static void main(String[] args) { Property p = new BusinessProperty("name", 1000); p.bidReceived("BIDDER", 500); // 500 System.out.println(p.getHighestBid()); p.bidReceived("BIDDER2", 1100); // 1100 System.out.println(p.getHighestBid()); // true System.out.println(p.isSold());
package del5_8; public class BusinessProperty extends Property { /** * BusinessProperty should implement the following extensions from Prope rty. As * soon as a bid is received that is equal to or higher than the price, the * property should be marked as sold */ public BusinessProperty(String name, int price) { super(name, price); } @Override /** * Creates a new bid and notifies any listeners that the bid has been received * If the bid is higher oe equal than the asking price, the property should be * registered as sold * * @param bidder the name of the bidder * @param bid the amount of the bid */ public void bidReceived(String bidder, int bid) { super.bidReceived(bidder, bid); if (bid >= this.getPrice()) { this.setIsSold(); } } public static void main(String[] args) { Property p = new BusinessProperty("name", 1000); p.bidReceived("BIDDER", 500); // 500 System.out.println(p.getHighestBid()); p.bidReceived("BIDDER2", 1100); // 1100 System.out.println(p.getHighestBid()); // true System.out.println(p.isSold()); } }
Implementer metodene i Realtor
- Realtor(double comission) oppretter et Realtor objekt med en gitt provisjon
- setCommission(double comission) Oppdaterer provisjonen til megleren
- addProperty(Property property) Legger til en eiendom i porteføljen til megleren
- calculateTotalCommission() - Regner ut total provisjonslønn basert på alle solgte boliger megleren har
- iterator() - Returnerer en iterator for å iterere gjennom alle eiendommene til megleren
package del5_8; import java.util.Iterator; public class Realtor implements Iterable<Property> { /** * Creates a Realtor object * * @param name the name of the realtor * @param commission the commission the realtor takes for a sale */ public Realtor(String name, double commission) { // TODO } /** * * @return the name of the realtor */ public String getName() { // TODO return null; } /** * * @param commission the new commission of the realtor * * @throws IllegalArgumentException if the commission not between (excluding) 0 * and (including) 100. */ public void setCommission(double commission) { // TODO } /** * Adds a property to the realtor's sale collection * * @param property a property */ public void addProperty(Property property) { // TODO } /** * The total commission is calculated as the sum of the highest bid of each sold * property times the commission rate. The commission rate is calculated based * on the realtor's current commission rate and does not need to consider * historical commission rates * * A realtor with commission of 10 %, and two sold properties sold at 1000 each, * would have a total commission value of 200 * * @return the calculated commission of the realtor */ public double calculateTotalCommission() { // TODO return 0; } @Override public Iterator<Property> iterator() { // TODO Auto-generated method stub return null; } /** * * @return an iterator to be able to iterate through all the properties of this * realtor */ public Iterator<Property> iterable() { return null; } public static void main(String[] args) { Realtor realtor = new Realtor("test", 10); // The following will only work if BusinessProperty and Property has the correct // implementation Property p = new Property("name", 1500); p.bidReceived("BIDDER", 2000); p.setIsSold(); realtor.addProperty(p); // Should be 200 System.out.println(realtor.calculateTotalCommission()); } }
package del5_8; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Realtor implements Iterable<Property>{ private List<Property> properties = new ArrayList<>(); private double commission; private String name; /** * Creates a Realtor object * * @param name the name of the realtor * @param comission the commission the realtor takes for a sale */ public Realtor(String name, double commission) { this.setCommission(commission); this.name = name; } public String getName() { return this.name; } /** * * @param comission the new comission of the realtor * * @throws IllegalArgumentException if the commission not between (excluding) 0 * and (including) 100. */ public void setCommission(double commission) { if (commission <= 0 || commission > 100) { throw new IllegalArgumentException("Comission must be between 0 and 100"); } this.commission = commission; } /** * Adds a property to the realtor's sale collection * * @param property a property */ public void addProperty(Property property) { this.properties.add(property); } /** * The total comission is calculated as the sum of the highest bid of each sold * property times the commission rate The comission rate is calculated based on * the realtor's current commission rate and does not need to consider * historical commission rates * * @return the calculated commission of the realtor */ public double calculateTotalCommission() { return this.properties.stream().filter(p -> p.isSold()).mapToDouble(Property::getHighestBid) .map(price -> price * (commission) / 100.0).sum(); } @Override public Iterator<Property> iterator() { return this.properties.iterator(); } public String toString() { return this.name; } public static void main(String[] args) { Realtor realtor = new Realtor("test", 10); // Will only work if BusinessProperty and Property has the correct // implementation Property p = new Property("name", 1500); p.bidReceived("BIDDER", 2000); p.setIsSold(); realtor.addProperty(p); // Should be 200 System.out.println(realtor.calculateTotalCommission()); } }
Implementer metoden i RealtorComparator
sortRealtorsByHighestBidReceived - Returnerer en Comparator som sorterer en liste med Realtor-objekter. Disse skal sorteres etter hvilken megler som har oppnådd det høyeste budet basert på alle eiendommene fra høyest til lavest
package del5_8; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; public class RealtorComparator { /** * * @return a comparator that sorts Realtor objects based on the highest bid they * have received on any of their properties from highest to lowest * * Example output with a list of one "realtor1" with two properties, * property1 with highest bid 1000, and property2 with highest bid 2000, * and a second "realtor2" with one property with the highest bid of * 500, and a third "realtor3" with one property with the highest bid of * 3000 would yield the following result * * realtor3 * realtor1 * realtor2 * * I.e: This sorts by the highest, single sale, and not the total of * sales for each realtor. * * */ public static Comparator<Realtor> sortRealtorsByHighestBidReceived() { return null; } public static void main(String[] args) { // This may not yield the correct results if Property/BusinessProperty/Realtor // has not been correctly implemented Realtor realtor = new Realtor("test1", 10); Realtor realtor2 = new Realtor("test2", 10); Property p = new BusinessProperty("name", 1500); p.bidReceived("BIDDER", 2000); Property p2 = new BusinessProperty("name2", 1000); p2.bidReceived("BIDDER", 1500); realtor.addProperty(p); realtor2.addProperty(p2); List<Realtor> realtors = Arrays.asList(realtor2, realtor); System.out.println(realtors); Collections.sort(realtors, sortRealtorsByHighestBidReceived()); // A more useful to string method or using the debugger might be helpful here // Should be in the opposite direction with realtor, and then realtor2 System.out.println(realtors); } }
package del5_8; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; public class RealtorComparator { /** * * @return a comparator that sort Realtor objects based on the highest bid they * have received on any of their properties from highest to lowest * * Example output with a list of one "realtor1" with two properties, * property1 with highest bid 1000, and property2 with highest bid 2000, * and a second "realtor2" with one property with the highest bid of * 500, and a third "realtor3" with one property with the highest bid of * 3000 would yield the following result * * realtor3 * realtor1 * realtor2 * * */ public static Comparator<Realtor> sortRealtorsByHighestBidReceived() { return (Realtor r1, Realtor r2) -> { int highestBidR1 = 0; for (Property property: r1) { highestBidR1 = Math.max(highestBidR1, property.getHighestBid()); } int highestBidR2 = 0; for (Property property: r2) { highestBidR1 = Math.max(highestBidR2, property.getHighestBid()); } return highestBidR2-highestBidR1; }; } public static void main(String[] args) { // This may not yield the correct results if Property/BusinessProperty/Realtor has not been correctly implemented Realtor realtor = new Realtor("test1", 10); Realtor realtor2 = new Realtor("test2", 10); Property p = new BusinessProperty("name", 1500); p.bidReceived("BIDDER", 2000); Property p2 = new BusinessProperty("name2", 1000); p2.bidReceived("BIDDER", 1500); realtor.addProperty(p); realtor2.addProperty(p2); List<Realtor> realtors= Arrays.asList(realtor2, realtor); System.out.println(realtors); Collections.sort(realtors, sortRealtorsByHighestBidReceived()); // A more useful to string method or using the debugger might be helpful here System.out.println(realtors); } }
Fyll ut UniversityHandbookUtils sine metoder for operasjoner på en liste med Course-objekter.
- getCourseNames(List courses) - Returnerer en liste med navnene til alle emnene
- getCourseProperties(List courses, Function<Course, String> function) - Returnerer alle emner transformerte ved hjelp av funksjonen
- calculateGradesSummary(List courses, BinaryOperator operator) - Returnerer resultatet av å kjøre operatoren på alle karaktersnittene til emnene
- getCoursesYouCanTake(List courses, List takenCourses) - Returnerer alle emnene hvor du tilfredstiller alle forkunnskapskravene (takenCourses representerer her emnene du tidligere har tatt)
package del9; import java.util.ArrayList; import java.util.Collection; import java.util.List; public class Course { private String courseName; private List<Course> prerequisites = new ArrayList<>(); 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; } public void addPrequisite(Course course) { this.prerequisites.add(course); } public Collection<Course> getPrerequisites() { return new ArrayList<>(prerequisites); } public String toString() { return this.courseName; } } package del9; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.function.BinaryOperator; import java.util.function.Function; public class UniversityHandbookUtils { /** * * @param courses List of course objects * @return a list of course names */ public static Collection<String> getCourseNames(Collection<Course> courses) { // TODO return Arrays.asList(); } /** * * @param courses List of course objects * @return a list of a course objects transformed by the function */ public static Collection<String> getCourseProperties(Collection<Course> courses, Function<Course, String> function) { // TODO return Arrays.asList(); } /** * * @param courses a list of course objects * @param operator a binary operator * @return the result of applying the operator across all average grades */ public static double calculateGradesSummary(Collection<Course> courses, BinaryOperator<Double> operator) { // TODO return 0; } /** * * @param courses List of course objects * @param takenCourses List of course objects * @return a list of courses where takenCourses contains all prerequisites * needed to enroll in the course */ public static Collection<Course> getCoursesYouCanTake(Collection<Course> courses, Collection<Course> takenCourses) { // TODO return Arrays.asList(); } public static void main(String[] args) { Course tdt4109 = new Course("TDT4109", 3.23); Course tdt4100 = new Course("TDT4100", 3.23); Course tdt4120 = new Course("TDT4120", 3.23); Course tdt1337 = new Course("TDT1337", 3.23); Course tdt3713 = new Course("TDT3713", 3.23); tdt4100.addPrequisite(tdt4109); tdt4120.addPrequisite(tdt4109); tdt4120.addPrequisite(tdt4100); tdt1337.addPrequisite(tdt3713); tdt3713.addPrequisite(tdt1337); List<Course> courses = Arrays.asList(tdt4109, tdt4100, tdt4120, tdt1337, tdt3713); // These two lines should print the same list of course names System.out.println(getCourseNames(courses)); System.out.println(getCourseProperties(courses, c -> c.getCourseName())); // Should print 16.15 System.out.println(calculateGradesSummary(courses, (prevGrade, currentGrade) -> prevGrade + currentGrade)); // Should print tdt4109, tdt4100 (order does not matter) System.out.println(getCoursesYouCanTake(courses, Arrays.asList(tdt4109))); } }
package del9; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.stream.Collectors; public class UniversityHandbookUtils { /** * * @param courses List of course objects * @return a list of course names */ public static List<String> getCourseNames(Collection<Course> courses) { return courses.stream().map(Course::getCourseName).collect(Collectors.toList()); } /** * * @param courses List of course objects * @return a list of a course objects transformed by the function */ public static Collection<String> getCourseProperties(Collection<Course> courses, Function<Course, String> function) { return courses.stream().map(function).collect(Collectors.toList()); } /** * * @param courses a list of course objects * @param operator a binary operator * @return a summary of all the grades of the courses by applying the binary * operator */ public static double calculateGradesSummary(Collection<Course> courses, BinaryOperator<Double> operator) { return courses.stream().map(Course::getAverageGrade).reduce(operator).get(); } /** * * @param courses List of course objects * @param takenCourses List of course objects * @return a list of courses where takenCourses contains all prerequisites * needed to enroll in the course */ public static Collection<Course> getCoursesYouCanTake(Collection<Course> courses, Collection<Course> takenCourses) { return courses.stream().filter(course -> takenCourses.containsAll(course.getPrerequisites())) .collect(Collectors.toList()); } public static void main(String[] args) { Course tdt4109 = new Course("TDT4109", 3.23); Course tdt4100 = new Course("TDT4100", 3.23); Course tdt4120 = new Course("TDT4120", 3.23); Course tdt1337 = new Course("TDT1337", 3.23); Course tdt3713 = new Course("TDT3713", 3.23); tdt4100.addPrequisite(tdt4109); tdt4120.addPrequisite(tdt4109); tdt4120.addPrequisite(tdt4100); tdt1337.addPrequisite(tdt3713); tdt3713.addPrequisite(tdt1337); List<Course> courses = Arrays.asList(tdt4109, tdt4100, tdt4120, tdt1337, tdt3713); // These two lines should print the same list of course names System.out.println(getCourseNames(courses)); System.out.println(getCourseProperties(courses, c -> c.getCourseName())); // Should print 16.15 System.out.println(calculateGradesSummary(courses, (prevGrade, currentGrade) -> prevGrade + currentGrade)); // Should print tdt4109, tdt4100 (order does not matter) System.out.println(getCoursesYouCanTake(courses, Arrays.asList(tdt4109))); } }
Ta utgangspunkt i TestableClass. De to metodene utenom konstruktøren har feil i implementasjonen, eller håndterer ikke alle tilfeller like godt.
Fyll ut testmetodene i TestableClassTest i src/test/java/del10 som skal eksponere feilene. (Testen bør ikke bestå)
- testIsMyStringEqualsToYieldsWrongResult() - Fanger opp et tilfelle hvor isMyStringEqualsTo gir feil resultatet
- testIncrementIntegerHandlesEdgeCases() - Fanger opp et tilfelle hvor getMyIntegerIncrement ikke oppfører seg slik den skal.
package del10; public class TestableClass { private Integer myInteger; private String myString; public TestableClass(Integer myInteger, String myString) { this.myInteger = myInteger; this.myString = myString; } /** * * @param otherString a string * @return whether myString text value is equal to the otherString */ public boolean isMyStringEqualTo(String otherString) { return this.myString == otherString; } /** * * @return myInteger + 1; */ public Integer getMyIntegerIncrement() { return this.myInteger + 1; } } package del10; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class TestableClassTest { @Test public void testIsMyStringEqualsToYieldsWrongResult() { } @Test public void testIncrementIntegerHandlesEdgeCases() { } }
package del10; public class TestableClass { private Integer myInteger; private String myString; public TestableClass(Integer myInteger, String myString) { this.myInteger = myInteger; this.myString = myString; } /** * * @param otherString a string * @return whether myString text value is equal to the otherString */ public boolean isMyStringEqualTo(String otherString) { return this.myString == otherString; } /** * * @return myInteger + 1; */ public Integer getMyIntegerIncrement() { return this.myInteger + 1; } } package del10; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class TestableClassTest { @Test public void testIsMyStringEqualsToYieldsWrongResult() { TestableClass test = new TestableClass(1, "test"); String equalString = new String("test"); Assertions.assertTrue(test.isMyStringEqualTo(equalString)); } @Test public void testIncrementIntegerHandlesEdgeCases() { TestableClass test = new TestableClass(null, "test"); Assertions.assertNull(test.getMyIntegerIncrement()); } }