OOP2

Change to Reservation class in order to make it work properly

Adds a series of changes, mostly in terms of the Reservation occupancy. Requires extra work in the view and controller classes as well, but should be solid enough for later additions.

Author
Vngngdn
Date
Dec. 10, 2016, 5:49 p.m.
Hash
607ccd02260ec7cfe256edf8c459db78dd6d2feb
Parent
55a08080f586d3dc3f876e048613c7daff2a163e
Modified files
Challenge 6/Reservation.java
Challenge 6/ReservationController.java

Challenge 6/Reservation.java

95 additions and 2 deletions.

View changes Hide changes
1
1
import java.util.HashSet;
2
2
import java.util.Date;
3
3
4
4
/**
5
5
 * Represents a reservation in a hostel.
6
6
 * Reservation is a simple class that allows one to store reservation
7
7
 * information, request it when necessary, and so on.
8
8
 * Certain methods are provided for interaction, which use contracts to assert
9
9
 * proper functioning.
10
10
 * @author Maarten Vangeneugden - 1438256
+
11
 * Note: There is a form of redundancy in this class.
+
12
 * Reservation holds a Set of Beds, and an integer, indicating the amount of
+
13
 * people that are in this Reservation.
+
14
 * Normally, the amount of people in the Reservation is determined by the amount
+
15
 * of reserved Beds, because the amount of Beds implied the amount of people to
+
16
 * facilitate.
+
17
 * Because of the design of this program, I've weighed the advantages and
+
18
 * disadvantages of holding this implication, of using a seperate member
+
19
 * explicitely indicating the amount of people.
+
20
 *
+
21
 * I've chosen the latter option. It scales better in terms of weird
+
22
 * afterthoughts ("I also want to make people sleep on the floor"), but being
+
23
 * explicit is also a tad easier to manage. It also allows the other classes to
+
24
 * be far more decoupled from Reservation (otherwise, they'd have to check for
+
25
 * errors every time themselves, hindering cohesiveness).
+
26
 *
+
27
 * To overcome the possible difference, I've made it so that, every time, the
+
28
 * relation between the values is changed (the people in the Reservation
+
29
 * changes, for example), the class automatically checks if the values are
+
30
 * corresponding. If they're not, a warning is printed to system.out.err,
+
31
 * informing about the fact that there's a discrepancy.
+
32
 *
+
33
 * I think that's the best way to overcome this problem.
+
34
 * @author Maarten Vangeneugden - 1438256
11
35
 */
12
36
public class Reservation {
13
37
14
38
	// Members
15
39
	private String groupName;
16
40
	private Date begin;
17
41
	private Date end;
18
42
	private Set<Bed> reservedBeds;
19
43
	private int reservationID;
+
44
	private int reservationID;
20
45
	private String roomType; // Room type requested by group
21
46
	private Set<String> roomFacilities; // Requested room facilities
22
47
	private Set<Date> breakfastDays; // Set of days the group wants breakfast
23
48
	// Controllers
24
49
	private RoomController roomController;
25
50
	private ReservationController reservationController;
26
51
27
52
	/**
28
53
	 * Create a new Reservation.
29
54
	 * Be aware about the limitations of a Reservation: it's not the
30
55
	 * Reservation's duty to check whether the provided Beds are properly
31
56
	 * reserved; take care of this accordingly.
32
57
	 * 
33
58
	 * Some information is implicit. For example: The size of the set of
34
59
	 * reserved Beds implies the amount of people in the group; no breakfast
35
60
	 * days implies no breakfast, ...
36
61
	 * @param groupName The name of the group.
37
62
	 * @param begin The date that the Reservation begins.
+
63
	 * @param begin The date that the Reservation begins.
38
64
	 * @param end The date that the Reservation ends.
39
65
	 * @param reservedBeds The set of Beds reserved and assigned to this
40
66
	 * Reservation.
41
67
	 * @param roomType The requested room type.
42
68
	 * @param roomFacilities The set of all requested room facilities.
43
69
	 * @param breakfastDays A set of all days that the group wants breakfast.
44
70
	 * @param reservationID An ID for this reservation, to differentiate from
45
71
	 * other Reservations.
46
72
	 * @pre No parameter must be a null pointer.
47
73
	 * @pre begin must come before end.
+
74
	 * @pre begin must come before end.
48
75
	 * @pre All dates in breakfastDays must fall between begin and end.
49
76
	 * @pre No string parameter may be empty.
50
77
	 * @post The amount of people in the Reservation is determined by the amount
51
78
	 * of reserved Beds.
52
79
	 * @throws NullPointerException if any parameter is a null pointer.
53
80
	 * @throws IllegalArgumentException if any of the other preconditions is not
54
81
	 * met.
55
82
	 */
56
83
	public Reservation(String groupName, Date begin, Date end, Set<Bed> reservedBeds, String roomType, Set<String> roomFacilities) {
57
-
		// Contract validation:
+
84
		// Contract validation:
58
85
		if(!begin.before(end)) {
+
86
			throw IllegalArgumentException("The amount of people should be at least 1.");
+
87
		}
+
88
		if(!begin.before(end)) {
59
89
			throw IllegalArgumentException("The begin date occurs after the end date.");
60
90
		}
61
91
		if(groupName.isEmpty() || roomType.isEmpty()) {
62
92
			throw IllegalArgumentException("groupName and/or roomType were empty strings.");
63
93
		}
64
94
		for(String roomFacility: roomFacilities) {
65
95
			if(roomFacility.isEmpty()) {
66
96
				throw IllegalArgumentException("One of the room facilities was an empty string.");
67
97
			}
68
98
		}
69
99
		for(Date breakfastDay : breakfastDays) {
70
100
			if(breakfastDay.before(begin) || breakfastDay.after(end)) {
71
101
				throw IllegalArgumentException("One of the breakfast days occurs before/after the reservation period.");
72
102
			}
73
103
		}
74
104
		// Contract validated, execute constructor
75
105
		this.groupName = groupName;
76
106
		this.beginDate = begin;
+
107
		this.beginDate = begin;
77
108
		this.endDate = end;
78
109
		this.reservedBeds = reservedBeds;
79
110
		this.reservationID = reservationID;
80
111
		this.roomType = roomType;
81
112
		this.roomFacilities = roomFacilities;
82
113
		this.breakfastDays = breakfastDays
83
114
	}
84
115
85
116
	/**
+
117
	 * Checks whether the amount of people corresponds with the reserved Beds.
+
118
	 * Call this method whenever a change in the amount of Beds, or the amount
+
119
	 * of people is made, or, whenever you need to assure consistency.
+
120
	 *
+
121
	 * It also prints a warning to system.out.err to inform about a discrepancy,
+
122
	 * should one be found.
+
123
	 *
+
124
	 * @return True if the counts are consistent, false otherwise.
+
125
	 */
+
126
	private boolean checkPeopleCountConsistency() {
+
127
		int people = this.getPeople();
+
128
		int beds = this.getReservedBeds().size();
+
129
		if(people != beds) {
+
130
			system.out.err("There's a discrepancy in the amount of people in Reservation"+
+
131
					this.reservationID +":");
+
132
			system.out.err("People: "+String.valueOf(people));
+
133
			system.out.err("Reserved Beds: "+String.valueOf(beds));
+
134
			return false;
+
135
		}
+
136
		return true;
+
137
	}
+
138
+
139
	/**
86
140
	 * Set the group name for this Reservation.
87
141
	 * @param groupName The new group name.
88
142
	 * @pre groupName mustn't be empty, or a null pointer.
89
143
	 * @post The group name is changed to the given name.
90
144
	 * @throws NullPointerException if groupName is a null pointer.
91
145
	 * @throws IllegalArgumentException if groupName is an empty String.
92
146
	 */
93
147
	public void setGroupName(String groupName) {
94
148
		if(groupName.isEmpty())
95
149
			throw IllegalArgumentException("groupName is an empty String.");
96
150
		this.groupName = groupName;
97
151
	}
98
152
99
153
	public String getGroupName() {
+
154
	 * Retrieve the current group name.
+
155
	 * @return The group name of this Reservation.
+
156
	 */
+
157
	public String getGroupName() {
100
158
		return groupName;
101
-
	}
+
159
	}
102
160
103
161
	/**
+
162
	 * Get amount of people in this Reservation.
+
163
	 * @post A warning will be printed to system.out.err if the amount of people
+
164
	 * is inconsistent with the amount of reserved Beds.
+
165
	 * @see Reservation.checkPeopleCountConsistency
+
166
	 * @return The amount of people in this Reservation.
+
167
	 */
+
168
	public int getPeople() {
+
169
		return this.people;
+
170
	}
+
171
+
172
	/**
+
173
	 * Set the amount of people for this Reservation.
+
174
	 * Note that this method will not notify you if the new amount of people is
+
175
	 * equal to the previous amount.
+
176
	 * 
+
177
	 * This method will print
+
178
	 * @param people The new amount of people in this Reservation.
+
179
	 * @pre people must be at least 1.
+
180
	 * @post A warning will be printed to system.out.err if the amount of people
+
181
	 * is inconsistent with the amount of reserved Beds.
+
182
	 * @post The amount of people is changed to the given value.
+
183
	 * @throws IllegalArgumentException if people is less than 1.
+
184
	 */
+
185
	public void setPeople(int people) {
+
186
		if(people < 1) {
+
187
			throw IllegalArgumentException("people must be at least 1.");
+
188
		}
+
189
		this.people = people;
+
190
		this.checkPeopleCountConsistency();
+
191
	}
+
192
	/**
104
193
	 * Set the begin date for this Reservation.
105
194
	 * @param begin The new begin date.
106
195
	 * @pre begin mustn't be a null pointer.
107
196
	 * @pre begin must come strictly before the end date.
108
197
	 * @post The begin date is updated accordingly.
109
198
	 * @throws NullPointerException if begin is a null pointer.
110
199
	 * @throws IllegalArgumentException if begin comes after the end date.
111
200
	 */
112
201
	public void setBegin(Date begin) {
113
202
		if(!begin.before(this.getEnd()))
114
203
			throw IllegalArgumentException("begin comes after the end date.")
115
204
		this.begin = begin;
116
205
	}
117
206
118
207
	
119
208
120
209
	/**
121
210
	 * Set the end date for this Reservation.
122
211
	 * @param end The new end date.
123
212
	 * @pre end mustn't be a null pointer.
124
213
	 * @pre end must come strictly after the begin date.
125
214
	 * @post The end date is updated accordingly.
126
215
	 * @throws NullPointerException if end is a null pointer.
127
216
	 * @throws IllegalArgumentException if end comes after the end date.
128
217
	 */
129
218
	public Date getDate() {
130
219
		return date;
131
220
	}
132
221
133
222
	public void setReservedBeds(Set<Bed> reservedBeds) {
134
223
		this.reservedBeds = reservedBeds;
135
224
	}
+
225
	}
136
226
137
227
	public Set<Bed> getReservedBeds() {
138
228
		return reservedBeds;
139
229
	}
+
230
	}
140
231
141
232
	public void setReservationID(int reservationID) {
+
233
	// copy/pasting. pfffff
+
234
	public void setReservationID(int reservationID) {
142
235
		this.reservationID = reservationID;
143
236
	}
144
237
145
238
	public int getReservationID() {
146
239
		return reservationID;
147
240
	}
148
241
149
242
	public void setRoomType(String roomType) {
150
243
		this.roomType = roomType;
151
244
	}
152
245
153
246
	public String getRoomType() {
154
247
		return roomType;
155
248
	}
156
249
157
250
	public void setRoomFacilities(Set<String> roomFacilities) {
158
251
		this.roomFacilities = roomFacilities;
159
252
	}
160
253
161
254
	public Set<String> getRoomFacilities() {
162
255
		return roomFacilities;
163
256
	}
164
257
165
258
	/**
166
259
	 * Calculates the price of the Reservation, based on its current state.
167
260
	 * Price table:
168
261
	 * - 20/person/day
169
262
	 *   - 5 less in low season, 5 more in high season
170
263
	 * - 4/breakfast ordered
171
264
	 * - If room is fully booked by the group --> 10% discount
172
265
	 * @return The price in euros.
173
266
	 */
174
267
	public int getPrice() {
175
268
		int totalPrice = 0;
176
269
		// Jan - Apr: Mid
177
270
		// May - Aug: High
178
271
		// Sep - Dec: Low
179
272
		
180
273
		// Calculate bed prices
181
274
		int month = this.getDate().getMonth();
182
275
		int bedPrice = 20;
183
276
		if(month >=8) { // From September:
184
277
			bedPrice -= 5;
185
278
		} else if(month >=4) { // From May:
186
279
			bedPrice += 5;
187
280
		}
188
281
		totalPrice += (this.getReservedBeds().size() * this.getNights() * bedPrice);
189
282
		// Calculate price for breakfasts
190
283
		int breakfasts = this.getBreakfastDays().length;
191
284
		totalPrice += breakfasts * this.getReservedBeds().size();
192
285
		// Check if eligible for discount
193
286
		for(Room room: roomController.getRooms()) {
194
287
			Set<Bed> roomBeds = room.getBeds();
195
288
			if(roomBeds.containsAll(this.reservedBeds)) {
196
289
				double discount = (double)totalPrice * 0.1;
197
290
				totalPrice -= (int)discount;
198
291
			}
199
292
		}
200
293
		return totalPrice;
201
294
	}
202
295
203
296
204
297
205
298
206
299
207
300
208
301
209
302
	public void setBreakfastDays(int[] breakfastDays) {
210
303
		this.breakfastDays = breakfastDays;
211
304
	}
212
305
	public int[] getBreakfastDays() {
213
306
		return this.breakfastDays;
214
307
	}
215
308
216
309
}
217
310

Challenge 6/ReservationController.java

1 addition and 3 deletions.

View changes Hide changes
1
1
import java.util.HashSet;
2
2
import java.util.Date;
3
3
4
4
/**
5
5
 * Controller class for the Reservations of this program.
6
6
 * Since this program handles a youth hostel, it's imperative that it holds a
7
7
 * number of Reservations.
8
8
 * 
9
9
 * ReservationController takes the responsibility of handling the addition,
10
10
 * cancelling, editing, ... of Reservations, and the related tasks inherent to
11
11
 * these responsibilities, such as reserving beds, generating IDs, ...
12
12
 * @author Maarten Vangeneugden - 1438256
13
13
 */
14
14
public class ReservationController {
15
15
16
16
	/* Rationale:
17
17
	 * Normally I'd put this as an interface (Set), but an interface does not
18
18
	 * inherit from Object, and thus, does not provide clone(). This is
19
19
	 * necessary, because otherwise, there's no point in having private
20
20
	 * members.
21
21
	 */
22
22
	private HashSet<Reservation> reservations; // Holds all Reservations
23
23
24
24
	/**
25
25
	 * Creates the ReservationController.
26
26
	 */
27
27
	public ReservationController() {
28
28
		this.reservations = new HashSet<>();
29
29
	}
30
30
31
31
	/**
32
32
	 * Returns a copy of all Reservations.
33
33
	 * Emphasis on "copy"; There is no setReservations() for a reason, using
34
34
	 * this to edit the pointer variable would omit the use of 'private'.
35
35
	 * @return A verbatim copy of all Reservations.
36
36
	 */
37
37
	@SuppressWarnings("unchecked")
38
38
	public Set<Reservation> getReservations() {
39
39
		return (HashSet<Reservation>)this.reservations.clone();
40
40
	}
41
41
42
42
	/**
43
43
	 * Generates a unique ID for a new Reservation.
44
44
	 * This method is to be called when a new Reservation is to be stored.
45
45
	 * As every Reservation carries an ID, this method searches for a unique
46
46
	 * one, and returns it.
47
47
	 * @return An integer, different from all other stored Reservation IDs.
48
48
	 */
49
49
	public int generateReservationID() {
50
50
		/* Small optimization idea:
51
51
		 * Instead of starting from 0, and incrementing until it's unique, it
52
52
		 * will take the amount of stored Reservations, and test that as an ID.
53
53
		 * This may still overlap (by removing an older Reservation), but may be
54
54
		 * much faster. Consider implemting and testing for effectiveness if
55
55
		 * generating an ID takes too long.
56
56
		 */
57
57
		int ID = 0;
58
58
		boolean isUnique = false;
59
59
		do {
60
60
			ID++;
61
61
			isUnique = true;
62
62
			for(Reservation reservation: this.reservations) {
63
63
				if(ID == reservation.getReservationID()) {
64
64
					isUnique = false;
65
65
				}
66
66
			}
67
67
		} while(!isUnique);
68
68
		// Test:
69
69
		for(Reservation reservation: this.reservations) {
70
70
			assert reservation.getReservationID() != ID : "Duplicate ID generated!";
71
71
		}
72
72
		return ID;
73
73
	}
74
74
	
75
75
	/** 
76
76
	 * Check if Reservation can be made.
77
77
	 * Call this method whenever you're planning on adding a new Reservation. It
78
78
	 * will check the provided requirements (Room facilities, for example), and
79
79
	 * return whether this Reservation can continue.
80
80
	 * @param reservation The Reservation to check for possible addition.
81
81
	 * @pre reservation mustn't be null.
82
82
	 * @throws NullPointerException if reservation is null.
83
83
	 * @return True if reservation can be added, False otherwise.
84
84
	 */
85
85
	public boolean checkReservation(Reservation reservation) {
86
86
		if(reservation == null) {
87
87
			throw NullPointerException("reservation was a null pointer.");
88
88
		}
89
89
		if(this.getRoomController().getQualifiedRooms(reservation).size() == 0) {
90
90
			return null;
91
91
	}
92
92
93
93
	/**
94
94
	 * Adds and confirms the reservation.
95
95
	 * By calling this method, the given reservation will be stored in the
96
96
	 * system, and the given room will be filled.
97
97
	 * You are to collect the necessary data, and assure yourself that all
98
98
	 * preconditions have been met.
99
99
	 * 
100
100
	 * The best way to accomplish this, is to only send 'sterile' Reservations
101
101
	 * as the first parameter. That is: Reservations without reserved Beds,
102
102
	 * without prior addition to the active Reservations, etc.
103
103
	 * NOTE: You must check for yourself if the Reservation can take place in
104
104
	 * this Room! If there are not enough Beds available, an exception will be
105
105
	 * thrown.
106
106
	 * @param reservation The Reservation to add.
107
107
	 * @param room The Room in which the people will reside.
108
108
	 * @param occupants The amount of people that need Beds.
109
-
	 * @pre occupants must be at least 1.
110
-
	 * @pre room must have enough empty beds.
111
109
	 * @pre room must accomodate the Reservation's requirements.
112
110
	 * @pre No parameter must be null.
113
111
	 * @pre reservation mustn't already be stored in the active Reservations.
114
112
	 * @post reservation is stored in the active Reservations.
115
113
	 * @post The Beds in the provided Room are reserved for the Reservation's
116
114
	 * period.
117
115
	 * @throws IllegalArgumentException if the given Room can't fulfill the
118
116
	 * requirements of the Reservation, or occupants is less than 1.
119
117
	 * @throws NullPointerException if any parameter is a null pointer.
120
118
	 */
121
119
	public void addReservation(Reservation reservation, int occupants, Room room) {
122
-
		// Contract validation
+
120
		// Contract validation
123
121
		if(occupants < 1)
124
122
			throw IllegalArgumentException("An invalid amount of occupants was given.");
125
123
		if(occupants > room.getEmptyBeds(reservation.getBegin(), reservation.getEnd()).size())
126
124
			throw IllegalArgumentException("The given Room has not enough empty Beds for the Reservation period.");
127
125
		if(!this.getRoomController().getQualifiedRooms(reservation).contains(room))
128
126
			throw IllegalArgumentException("The given Room cannot meet all requirements of the Reservation.");
129
127
		if(this.getReservations().contains(reservation)) {
130
128
			throw IllegalArgumentException("The given Reservation was already included as 
131
129
		
132
130
		
133
131
		// TODO: Add reservation to the set, and add the reserved days to the
134
132
		// beds in the given room.
135
133
	}
136
134
	/**
137
135
	 * Cancels and removes the given Reservation.
138
136
	 * If you want to remove a Reservation, use this method, and provide the
139
137
	 * Reservation up for removal.
140
138
	 * This method will take care of related actions, such as releasing Beds.
141
139
	 * @param reservation The Reservation to be removed.
142
140
	 * @pre reservation mustn't be null.
143
141
	 * @pre reservation must be contained in the active Reservations.
144
142
	 * @post The Reservation is removed from the active Reservations.
145
143
	 * @post The Beds, previously reserved for this Reservation, are now
146
144
	 * released, and can be reserved for another Reservation.
147
145
	 * @throws NullPointerException if reservation is a null pointer.
148
146
	 * @throws IllegalArgumentException if reservation is not contained in the
149
147
	 * active Reservations.
150
148
	 */
151
149
	public void cancelReservation(Reservation reservation) {
152
150
		// Contract validation
153
151
		if(!this.getReservations().contains(reservation)) {
154
152
			throw IllegalArgumentException("The given Reservation was not contained in the active Reservations.");
155
153
		}
156
154
		if(reservation == null) {
157
155
			throw NullPointerException();
158
156
		}
159
157
		// Contract validated, execute method
160
158
		this.reservations.remove(reservation); // Remove from active Reservations
161
159
		for(Bed bed: reservation.getReservedBeds()) { // Release reserved Beds
162
160
			bed.removeReservationPeriod(reservation.getBegin(), reservation.getEnd());
163
161
		}
164
162
		// Asserting post conditions are met
165
163
		assert !this.getReservation().contains(reservation) : "The reservation is still part of the active Reservations.";
166
164
		for(Bed bed: reservation.getReservedBeds()) {
167
165
			assert bed.isFree(reservation.getBegin(), reservation.getEnd()) : "One or more of the Beds are still reserved.";
168
166
		}
169
167
	}
170
168
171
169
}
172
170