OOP2

Add new design choice regarding the use of Strings instead of Enums

Author
Vngngdn
Date
Dec. 15, 2016, 11:51 p.m.
Hash
f68e848416b19091f2f20166cbd19ebec9fa4bc3
Parent
70c4f4fde97168ddd55ad491ce96bd3731314269
Modified files
Challenge 6/Reservation.java
Challenge 6/ReservationController.java
Challenge 6/ReservationView.java
Challenge 6/Room.java
Challenge 6/ontwerpkeuzes2.md

Challenge 6/Reservation.java

1 addition and 1 deletion.

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

Challenge 6/ReservationController.java

1 addition and 0 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
	private RoomController roomController;
24
24
25
25
	/**
26
26
	 * Creates the ReservationController.
27
27
	 * 
28
28
	 * WARNING: This program avoids the use of null pointers, but because of
29
29
	 * circular dependency issues, this class requires that the developer (which
30
30
	 * means YOU) set the RoomController reference member manually.
31
31
	 * Be advised that the setRoomController() method will not accept a null
32
32
	 * pointer.
33
33
	 *
34
34
	 * Once again: Set the RoomController reference manually ASAP. Failure to do
35
35
	 * so will cause this program to blow up. You've been warned.
36
36
	 * @see ReservationController.setRoomController
37
37
	 */
38
38
	public ReservationController() {
39
39
		this.reservations = new HashSet<>();
40
40
	}
41
41
42
42
	/**
43
43
	 * Returns a copy of all Reservations.
44
44
	 * Emphasis on "copy"; There is no setReservations() for a reason, using
45
45
	 * this to edit the pointer variable would omit the use of 'private'.
46
46
	 * @return A verbatim copy of all Reservations.
47
47
	 */
48
48
	@SuppressWarnings("unchecked")
49
49
	public Set<Reservation> getReservations() {
50
50
		return (HashSet<Reservation>)this.reservations.clone();
51
51
	}
52
52
53
53
	/**
54
54
	 * Generates a unique ID for a new Reservation.
55
55
	 * This method is to be called when a new Reservation is to be stored.
56
56
	 * As every Reservation carries an ID, this method searches for a unique
57
57
	 * one, and returns it.
58
58
	 * @return An integer, different from all other stored Reservation IDs.
59
59
	 */
60
60
	public int generateReservationID() {
61
61
		/* Small optimization idea:
62
62
		 * Instead of starting from 0, and incrementing until it's unique, it
63
63
		 * will take the amount of stored Reservations, and test that as an ID.
64
64
		 * This may still overlap (by removing an older Reservation), but may be
65
65
		 * much faster. Consider implemting and testing for effectiveness if
66
66
		 * generating an ID takes too long.
67
67
		 */
68
68
		int ID = 0;
69
69
		boolean isUnique = false;
70
70
		do {
71
71
			ID++;
72
72
			isUnique = true;
73
73
			for(Reservation reservation: this.reservations) {
74
74
				if(ID == reservation.getReservationID()) {
75
75
					isUnique = false;
76
76
				}
77
77
			}
78
78
		} while(!isUnique);
79
79
		// Test:
80
80
		for(Reservation reservation: this.reservations) {
81
81
			assert reservation.getReservationID() != ID : "Duplicate ID generated!";
82
82
		}
83
83
		return ID;
84
84
	}
85
85
	
86
86
	/** 
87
87
	 * Check if Reservation can be made.
88
88
	 * Call this method whenever you're planning on adding a new Reservation. It
89
89
	 * will check the provided requirements (Room facilities, for example), and
90
90
	 * return whether this Reservation can continue.
91
91
	 * @param reservation The Reservation to check for possible addition.
92
92
	 * @pre reservation mustn't be null.
93
93
	 * @throws NullPointerException if reservation is null.
94
94
	 * @return True if reservation can be added, False otherwise.
95
95
	 */
96
96
	public boolean checkReservation(Reservation reservation) {
97
97
		if(reservation == null) {
98
98
			throw NullPointerException("reservation was a null pointer.");
99
99
		}
100
100
		if(this.getRoomController().getQualifiedRooms(reservation).size() == 0) {
101
101
			return null;
102
102
	}
+
103
	}
103
104
104
105
	/**
105
106
	 * Adds and confirms the reservation.
106
107
	 * By calling this method, the given reservation will be stored in the
107
108
	 * system, and the given room will be filled.
108
109
	 * You are to collect the necessary data, and assure yourself that all
109
110
	 * preconditions have been met.
110
111
	 * 
111
112
	 * The best way to accomplish this, is to only send 'sterile' Reservations
112
113
	 * as the first parameter. That is: Reservations without reserved Beds,
113
114
	 * without prior addition to the active Reservations, etc.
114
115
	 * NOTE: You must check for yourself if the Reservation can take place in
115
116
	 * this Room! If there are not enough Beds available, an exception will be
116
117
	 * thrown.
117
118
	 * @param reservation The Reservation to add.
118
119
	 * @param room The Room in which the people will reside.
119
120
	 * @pre room must have enough empty beds.
120
121
	 * @pre room must accomodate the Reservation's requirements.
121
122
	 * @pre No parameter must be null.
122
123
	 * @pre reservation mustn't already be stored in the active Reservations.
123
124
	 * @post reservation is stored in the active Reservations.
124
125
	 * @post The Beds in the provided Room are reserved for the Reservation's
125
126
	 * period.
126
127
	 * @throws IllegalArgumentException if the given Room can't fulfill the
127
128
	 * requirements of the Reservation, or occupants is less than 1.
128
129
	 * @throws NullPointerException if any parameter is a null pointer.
129
130
	 */
130
131
	public void addReservation(Reservation reservation, Room room) {
131
132
		// Contract validation. Null pointers are implicitely checked by calling
132
133
		// methods.
133
134
		if(reservation.getPeople() > room.getEmptyBeds(reservation.getBegin(), reservation.getEnd()).size())
134
135
			throw IllegalArgumentException("The given Room has not enough empty Beds for the Reservation period.");
135
136
		if(!this.getRoomController().getQualifiedRooms(reservation).contains(room))
136
137
			throw IllegalArgumentException("The given Room cannot meet all requirements of the Reservation.");
137
138
		if(this.getReservations().contains(reservation))
138
139
			throw IllegalArgumentException("The given Reservation was already included in the active Reservations.");
139
140
		// Contract validated
140
141
		this.reservations.add(reservation);
141
142
		Bed[] beds = room.getEmptyBeds(reservation.getBegin(), reservation.getEnd()).toArray(new Bed[1]);
142
143
		Set<Bed> reservedBeds = new HashSet<>();
143
144
		for(int i=0; i<reservation.getPeople(); i++) {
144
145
			beds[i].reservePeriod(reservation.getBegin(), reservation.getEnd());
145
146
			reservedBeds.add(beds[i]);
146
147
		}
147
148
		reservation.setReservedBeds(reservedBeds);
148
149
	}
149
150
150
151
	/**
151
152
	 * Cancels and removes the given Reservation.
152
153
	 * If you want to remove a Reservation, use this method, and provide the
153
154
	 * Reservation up for removal.
154
155
	 * This method will take care of related actions, such as releasing Beds.
155
156
	 * @param reservation The Reservation to be removed.
156
157
	 * @pre reservation mustn't be null.
157
158
	 * @pre reservation must be contained in the active Reservations.
158
159
	 * @post The Reservation is removed from the active Reservations.
159
160
	 * @post The Beds, previously reserved for this Reservation, are now
160
161
	 * released, and can be reserved for another Reservation.
161
162
	 * @throws NullPointerException if reservation is a null pointer.
162
163
	 * @throws IllegalArgumentException if reservation is not contained in the
163
164
	 * active Reservations.
164
165
	 */
165
166
	public void cancelReservation(Reservation reservation) {
166
167
		// Contract validation
167
168
		if(!this.getReservations().contains(reservation)) {
168
169
			throw IllegalArgumentException("The given Reservation was not contained in the active Reservations.");
169
170
		}
170
171
		if(reservation == null) {
171
172
			throw NullPointerException();
172
173
		}
173
174
		// Contract validated, execute method
174
175
		this.reservations.remove(reservation); // Remove from active Reservations
175
176
		for(Bed bed: reservation.getReservedBeds()) { // Release reserved Beds
176
177
			bed.removeReservationPeriod(reservation.getBegin(), reservation.getEnd());
177
178
		}
178
179
		// Asserting post conditions are met
179
180
		assert !this.getReservation().contains(reservation) : "The reservation is still part of the active Reservations.";
180
181
		for(Bed bed: reservation.getReservedBeds()) {
181
182
			assert bed.isFree(reservation.getBegin(), reservation.getEnd()) : "One or more of the Beds are still reserved.";
182
183
		}
183
184
	}
184
185
185
186
}
186
187

Challenge 6/ReservationView.java

12 additions and 1 deletion.

View changes Hide changes
1
1
import java.util.Set;
2
2
import java.util.HashSet;
3
3
import java.util.Date;
4
4
/**
5
5
 * Creates a view screen that allows interaction with the reservation.
6
6
 * This window will place the reservation details in editable fields, so its
7
7
 * state can be adapted.
8
8
 * It then also adds a couple of buttons; add/update/cancel, with their
9
9
 * respective actions. These will then be passed to the ReservationController.
10
10
 * It will not allow to add/update a reservation if dates overlap, i.e. beds
11
11
 * can't be reserved for that period.
12
12
 * @author Maarten Vangeneugden - 1438256
13
13
 */
14
14
public class ReservationView {
15
15
16
16
	private Reservation reservation;
17
17
	private Window window;
18
18
19
19
	// Controllers for communication with the rest
20
20
	private ReservationController rc;
21
21
	private RoomController roc;
22
22
23
23
	// GUI widgets
24
24
	private JTextField nameField;
25
25
	private JSpinner amountPeopleField;
26
26
	private JTextField dateField;
27
27
	private JSpinner durationField;
28
28
	private JRadioButton[] typeField;
29
29
	private JCheckBox showerField;
30
30
	private JCheckBox bathField;
31
31
	private JCheckBox minibarField;
32
32
	private JCheckBox aircoField;
33
33
34
34
35
35
	/**
36
36
	 * Construct a window to edit a Reservation.
37
37
	 * This window presents its caller with the necessary tools to edit the
38
38
	 * given Reservation, and save it in the system.
39
39
	 *
40
40
	 * By sending it an empty Reservation, you can add a new Reservation to the
41
41
	 * system.
42
42
	 * This class is built in a way that allows it to be used for both creating
43
43
	 * new Reservations, and updating/changing existing Reservations.
44
44
	 * Existing Reservations can also be removed by clicking the appropriate
45
45
	 * button.
46
46
	 * @param reservation The Reservation that will be updated.
47
47
	 * @param rc The ReservationController class.
48
48
	 * @param roc The RoomController class.
49
49
	 * @pre No parameter may be a null pointer.
50
50
	 * @post A window is displayed with GUI widgets, which are filled in
51
51
	 * according to the state of reservation.
52
52
	 * @throws NullPointerException if any parameter is a null pointer.
53
53
	 */
54
54
	public ReservationView(Reservation reservation, ReservationController rc, RoomController roc) {
55
55
		// Contract validation
56
56
		if(rc == null || roc == null || reservation == null)
57
57
			throw NullPointerException("One or more of the given parameters is a null pointer.");
58
58
		// Contract validated
59
59
		this.rc = rc;
60
60
		this.roc = roc;
61
61
62
62
		this.reservation = reservation;
63
63
		this.window = new Window("Reservation screen");
64
64
		this.addFields();
65
65
	}
66
66
67
67
	public void setReservation(Reservation reservation) {
68
68
		this.reservation = reservation;
69
69
	}
70
70
71
71
	public Reservation getReservation() {
72
72
		return reservation;
73
73
	}
74
74
75
75
	/**
76
76
	 * Add the necessary fields to the window.
77
77
	 * This method inspects the Reservation, and copies the included information
78
78
	 * to the widget's content.
79
79
	 */
80
80
	private void addFields() {
81
81
		this.window.createLabel("Group name");
82
82
		this.nameField = window.createTextField(this.reservation.getGroupName());
83
83
		this.window.createLabel("Amount of people");
84
84
		this.amountPeopleField = window.createSpinner(1, 20, this.reservation.getPeople(), 1);
85
85
		// Formatting date for the date field:
86
86
		this.window.createLabel("Begin date");
87
87
		this.beginDateField = window.createTextField(this.reservation.getBegin().toString());
88
88
		this.window.createLabel("End date");
89
89
		this.endDateField = window.createTextField(this.reservation.getEnd().toString());
90
90
		String[] types = {"Male", "Female", "Mixed"};
91
91
		this.typeField = this.window.createRadioButtons(types);
92
92
		// TODO: Add a test to see if the Reservation has indicated which type
93
93
		// it is, and then already check the corresponding radio button.
94
94
		this.showerField = this.window.createCheckbox("Shower");
95
95
		this.bathField = this.window.createCheckbox("Bath");
96
96
		this.minibarField = this.window.createCheckbox("Minibar");
97
97
		this.aircoField = this.window.createCheckbox("Airco");
98
98
		// TODO: Idem for the facilities, test if already in Reservation, and
99
99
		// check accordingly.
100
100
		this.window.createButton("Add/Update reservation", "", "addReservation", this);
101
101
		this.window.createButton("Remove reservation", "", "removeReservation", this);
102
102
	}
103
103
104
104
	/**
105
105
	 * Start the addition of this Reservation to the system.
106
106
	 * This method will check the current fields, and update the Reservation
107
107
	 * with those values. In doing so, the validity of the values is checked
108
108
	 * (formatting, begin date before end date, ...).
109
109
	 * If everything is okay, the method will check if these changes are
110
110
	 * possible in the current system; are there enough empty beds?
111
111
	 *
112
112
	 * If everything is okay, the changes will be propagated to the
113
113
	 * Reservation's state, and (if it's a new Reservation) will be added to the
114
114
	 * system's active Reservations.
115
115
	 */
116
116
	public void addReservation() {
117
117
		// Collect all data from the fields
118
118
		String name = this.nameField.getText();
119
119
		Date beginDate = null, endDate = null;
120
120
		try {
121
121
			beginDate = DataFormat.parse(this.beginDateField.getText());
122
122
			endDate = DataFormat.parse(this.endDateField.getText());
123
123
		}
124
124
		catch(ParseException e) {
125
125
			this.window.messageDialog("Not all date fields were properly formatted.");
126
126
			return;
127
127
		}
128
128
		int people = (Integer)this.amountPeopleField.getValue();
129
129
		String type = "";
130
130
		for(int i=0; i<this.typeField.length; i++) {
131
131
			if(this.typeField[i].isSelected()) {
132
132
				type = this.typeField[i].getText();
133
133
				break;
134
134
			}
135
135
		}
136
136
		Set<String> facilities = new HashSet<>();
137
137
		if(this.showerField.isSelected()) {
138
138
			facilities.add("Shower");
139
139
		}
140
140
		if(this.bathField.isSelected()) {
141
141
			facilities.add("Bath");
142
142
		}
143
143
		if(this.minibarField.isSelected()) {
144
144
			facilities.add("Minibar");
145
145
		}
146
146
		if(this.aircoField.isSelected()) {
147
147
			facilities.add("Airco");
148
148
		}
149
149
150
150
		// TODO breakfast days handling
151
151
152
152
		//Set<Room> possibleRooms = this.roc.getQualifiedRooms(actualDate, duration, type, facilities);
153
153
		// TODO: Refactor upper method to work with the Reservation.
154
154
		// TODO: Implement all checks of valid data above this line!
155
155
		
156
156
		// Data validated; Try finding appropriate beds
157
157
		if(possibleRooms.size() == 0) {
158
158
			boolean tryAgain = this.window.confirmDialog("No rooms met the requirements! Would you like to continue and change the parameters?");
159
159
			if(!tryAgain) {
160
160
				// TODO close window
161
161
			}
162
162
		}
163
163
		else {
164
164
			Room pickedRoom = null;
165
165
			for(Room room: possibleRooms) {
166
166
				if(room.getEmptyBeds(actualDate, actualEndDate).size() < room.getBeds().size()) {
167
167
					// First, fill the rooms that are partially filled.
168
168
					pickedRoom = room;
169
169
					break;
170
170
				}
171
171
			}
172
172
			if(pickedRoom == null) { // If still no room, pick an empty room
173
173
				for(Room room: possibleRooms) {
174
174
					if(room.getEmptyBeds(actualDate, actualEndDate).size() >= amount) {
175
175
						pickedRoom = room;
176
176
						break;
177
177
					}
178
178
				}
179
179
			}
180
180
			assert pickedRoom != null;
181
181
			// TODO: Set reservation fields here!
182
182
			this.rc.addReservation(reservation, pickedRoom);
183
183
184
184
			// Confirm and show price:
185
185
			int price = this.reservation.getPrice();
186
186
			this.window.confirmDialog("Reservation confirmed! Price: " +String.valueOf(price));
187
187
		}
188
188
		
189
189
	}
190
190
191
191
	public void removeReservation() {
+
192
	 * Remove Reservation and the GUI.
+
193
	 * Calling this method will remove the Reservation, followed by closing this
+
194
	 * window.
+
195
	 * If the Reservation is active (i.e. saved in the ReservationController),
+
196
	 * it will be removed.
+
197
	 * Any changes will be cancelled.
+
198
	 */
+
199
	public void removeReservation() {
192
200
		// TODO: Close the window. That's all.
193
-
	}
+
201
			this.rc.cancelReservation(this.reservation);
+
202
		}
+
203
		this.window.close();
+
204
	}
194
205
}
195
206

Challenge 6/Room.java

1 addition and 1 deletion.

View changes Hide changes
1
1
import java.util.HashSet;
2
2
import java.util.Date;
3
3
4
4
/**
5
5
 * A room in a hostel.
6
6
 * Room represents just that: A room.
7
7
 * A room contains a set of Beds, facilities that can be used, etc.
8
8
 * It's highly decoupled: Apart from holding a set of Beds, the only members
9
9
 * types consist of those that are available in every OpenJDK implementation.
10
10
 * @author Maarten Vangeneugden - 1438256
11
11
 */
12
12
public class Room {
13
13
14
14
	private HashSet<Bed> beds;
15
15
	private String type;
16
16
	private HashSet<String> facilities;
17
17
18
18
	/**
19
19
	 * Create a new Room.
20
20
	 * @param beds The amount of Beds that will be placed in this Room.
21
21
	 * @param type The type of this Room. (for example: Male, Female, Mixed,
22
22
	 * ...)
23
23
	 * @param facilities A Set of facilities this Room provides ("Shower",
24
24
	 * "Radio", "Overpriced WiFi", ...)
25
25
	 * @pre No parameter must be a null pointer.
26
26
	 * @pre beds must be at least 1.
27
27
	 * @pre Type mustn't be an empty String.
28
28
	 * @pre No facility may be an empty String.
29
29
	 * @post The Room will receive the provided amount of Beds, which are all
30
30
	 * completely released.
31
31
	 * @throws IllegalArgumentException if the amount of Beds is less than 1, or
32
32
	 * one of the facilities is an empty String.
33
33
	 * @throws NullPointerException if one of the parameters is a null pointer.
34
34
	 */
35
35
	public Room(int beds, String type, Set<String> facilities) {
36
36
		// Contract validation happens in the setter methods
37
37
		this.setFacilities(facilities);
38
38
		this.setType(type)
39
-
		if(beds < 1) {
+
39
		if(beds < 1) {
40
40
			throw IllegalArgumentException("Beds was less than 1.");
41
41
		}
42
42
		// Contract validated, execute constructor
43
43
		this.beds = new HashSet<>();
44
44
		for(int i=0; i<beds; i++) {
45
45
			this.beds.add(new Bed());
46
46
		}
47
47
	}
48
48
49
49
	/**
50
50
	 * Remove a Bed from this Room.
51
51
	 * This method will remove the given Bed from this Room.
52
52
	 * However, make sure that this Bed is free of any reservations, as you
53
53
	 * can't delete a Bed with a reserved period.
54
54
	 * @see Bed
55
55
	 * @param bed The Bed to be removed.
56
56
	 * @pre bed mustn't be null.
57
57
	 * @pre bed mustn't be the last Bed in this Room.
58
58
	 * @pre bed must be in this Room.
59
59
	 * @pre bed mustn't have any reserved periods.
60
60
	 * @post The amount of Beds in this Room is decremented by 1.
61
61
	 * @throws IllegalArgumentException if bed is not in this Room, or has
62
62
	 * reserved periods, or this is the last Bed in the Room.
63
63
	 * @throws NullPointerException if bed is a null pointer.
64
64
	 */
65
65
	public void removeBed(Bed bed) {
66
66
		// Contract validation
67
67
		if(!this.getBeds().contains(bed)) {
68
68
			throw IllegalArgumentException("The given Bed is not in this Room.");
69
69
		}
70
70
		if(bed.hasReservations()) {
71
71
			throw IllegalArgumentException("The given Bed still has reserved periods.");
72
72
		}
73
73
		if(this.getBeds().size() == 1) {
74
74
			throw IllegalArgumentException("Deleting this Bed would empty the Room.");
75
75
		}
76
76
		// Contract validated, execute method
77
77
		this.beds.remove(bed);
78
78
		// Assert post conditions
79
79
		assert !this.getBeds().contains(bed) : "The given Bed was not removed from this Room.";
80
80
	}
81
81
82
82
	/**
83
83
	 * Add a Bed to this Room.
84
84
	 * @post The amount of Beds in this Room increments with 1.
85
85
	 */
86
86
	public void addBed() {
87
87
		this.beds.add(new Bed());
88
88
	}
89
89
90
90
	/**
91
91
	 * Returns a copy of all Beds.
92
92
	 * @return A verbatim copy of all Beds.
93
93
	 */
94
94
	@SuppressWarnings("unchecked")
95
95
	public Set<Bed> getBeds() {
96
96
		return (HashSet<Bed>) this.beds.clone();
97
97
	}
98
98
99
99
	/**
100
100
	 * Set the type of this Room.
101
101
	 * @param type The new type of the Room.
102
102
	 * @pre type mustn't be an empty String, or a null pointer.
103
103
	 * @post The Room's type is changed to the given type.
104
104
	 * @throws IllegalArgumentException if type is an empty String.
105
105
	 * @throws NullPointerException if type is a null pointer.
106
106
	 */
107
107
	public void setType(String type) {
108
108
		if(type.isEmpty()) {
109
109
			throw IllegalArgumentException("type is an empty String.");
110
110
		}
111
111
		this.type = type;
112
112
	}
113
113
114
114
	/**
115
115
	 * Returns the type of this Room.
116
116
	 * @return The secret launch codes of the USS Nimitz, granting access to
117
117
	 * nuclear warheads so big, you'll lose faith in humanity.
118
118
	 */
119
119
	public String getType() {
120
120
		return type;
121
121
	}
122
122
123
123
	/**
124
124
	 * Set the facilities available in this Room.
125
125
	 * @param facilities The set of facilities in this Room.
126
126
	 * @pre No facility must be an empty String or a null pointer.
127
127
	 * @post The Room will have the newly provided facilities.
128
128
	 * @throws IllegalArgumentException if one of the facilities is an empty String.
129
129
	 * @throws NullPointerException if any given variable is a null pointer.
130
130
	 */
131
131
	public void setFacilities(Set<String> facilities) {
132
132
		for(String facility : facilities) {
133
133
			if(facility.isEmpty()) {
134
134
				throw IllegalArgumentException("A facility was an empty String.");
135
135
			}
136
136
		}
137
137
		this.facilities = facilities;
138
138
	}
139
139
140
140
	/**
141
141
	 * Returns a copy of all facilities.
142
142
	 * @return A verbatim copy of all facilities.
143
143
	 */
144
144
	@SuppressWarnings("unchecked")
145
145
	public Set<String> getFacilities() {
146
146
		return (HashSet<String>)this.facilities.clone();
147
147
	}
148
148
149
149
	/**
150
150
	 * Search for Beds that can be reserved.
151
151
	 * This method will look through all Beds, and check whether they can be
152
152
	 * reserved in the given period. You will receive all Beds that can be
153
153
	 * reserved.
154
154
	 * @param begin The begin date.
155
155
	 * @param end The end date.
156
156
	 * @pre No parameter must be null.
157
157
	 * @pre begin must strictly come before end.
158
158
	 * @throws IllegalArgumentException if begin comes after end, or both are
159
159
	 * equal.
160
160
	 * @throws NullPointerException if any given parameter is a null pointer.
161
161
	 * @return A Set of all Beds that can be reserved, or an empty Set if no Bed
162
162
	 * can be reserved in the given period.
163
163
	 */
164
164
	public Set<Bed> getEmptyBeds(Date begin, Date end) {
165
165
		// Contract validation
166
166
		if(!begin.before(end)) {
167
167
			throw IllegalArgumentException("begin does not come strictly before end");
168
168
		}
169
169
		// Validated
170
170
		Set<Bed> emptyBeds = new HashSet<>();
171
171
		for(Bed bed: this.getBeds()) {
172
172
			if(bed.isFree(begin, end)) {
173
173
				emptyBeds.add(bed);
174
174
			}
175
175
		}
176
176
		return emptyBeds;
177
177
	}
178
178
179
179
}
180
180

Challenge 6/ontwerpkeuzes2.md

60 additions and 0 deletions.

View changes Hide changes
1
1
2
2
## GRASP
3
3
Om zoveel mogelijk tegemoet te komen aan de GRASP-richtlijnen, heb ik volgende
4
4
ontwerpkeuzes toegepast voor de verschillende richtlijnen.
5
5
6
6
### High cohesion & Low coupling
7
7
- Veel classes zijn totaal van elkaar losgekoppeld. Een goed voorbeeld hiervan
8
8
  is Bed; Bed weet niet over dat er Reservaties bestaan, zelfs niet in welke
9
9
  Room het 'staat'.
10
10
- Als er toch gekoppeld moet worden, dan blijft dit tot een minimum beperkt; Een
11
11
  Room weet wel welke Bedden het heeft, maar niet hoe deze gebruikt worden, een
12
12
  Reservation weet wel welke Bedden voor hem gereserveerd zijn, maar heeft geen
13
13
  weet van welke kamer dat deze staat.
14
14
- Uitzondering op deze regel vormen de Controller-classes; omwille van hun taken
15
15
  zijn deze vaak verplicht om van veel verschillende classes op de hoogte te
16
16
  zijn.
17
17
18
18
### Indirectie
19
19
- In plaats van functionaliteit toe te wijzen aan class X om met class Y te
20
20
  interageren, wordt er vaak gebruik gemaakt van een class Z, die deze
21
21
  verantwoordelijkheid op zich neemt.
22
22
- Dit wordt toegepast d.m.v. een MVC-structuur, waarin de \*Controller-classes
23
23
  als 'tussenpersoon' werken.
24
24
- Dit komt ook tegemoet aan de eigenschappen van Information Expertise.
25
25
26
26
### Creator
27
27
- Controllers staan ook in als zgn. Creators van de models die ze beheren. Ze
28
28
  voldoen dan ook aan de eigenschappen zoals
29
29
  [hier](https://en.wikipedia.org/wiki/GRASP_(object-oriented_design)#Creator)
30
30
  opgesomd wordt.
31
31
32
32
33
33
## SOLID
34
34
35
35
### Single Responsibility
36
36
37
37
## Algemene keuzes ter bevordering codekwaliteit
38
38
39
39
### Null pointers
+
40
In het programma zijn er sommige members die doen vermoeden dat ze beter als
+
41
Enums aangeduid kunnen worden; Het type van een kamer, faciliteiten, ...
+
42
+
43
In plaats van een speciale class hiervoor te maken, heb ik gekozen om deze
+
44
gewoon te behandelen als simpele Strings in lijsten.
+
45
+
46
Het voordeel aan deze werkwijze, is dat Strings in Java SE quasi universeel
+
47
voorkomen; data kunnen geconverteerd worden naar Strings (en vice versa), veel
+
48
gebruikte GUI-libraries (waaronder Swing, JavaFX, ...) gebruiken Strings voor
+
49
tekst voor te stellen in de GUI-widgets, ...
+
50
Daarnaast weet iedereen die ook maar een beetje geschoold is in Java, direct hoe
+
51
deze members behandeld kunnen worden. Had ik een class gemaakt die bv.
+
52
RoomFacilities heette, dan is die parate kennis over de taal zelf nutteloos.
+
53
+
54
Strings zijn ook voorzien van extreem veel methods, en zijn dus zeer flexibele
+
55
classes om te gebruiken. Het feit dat ze zo makkelijk doorheen het programma te
+
56
gebruiken zijn is dus een groot pluspunt.
+
57
+
58
Als dat nog niet genoeg is: Het gebruiken van de hulpmiddelen uit de _standard
+
59
library_ is niet enkel waarvoor libraries überhaupt bestaan, het beperkt ook
+
60
het benodigde aantal classes in de eigen software, waardoor het geheel
+
61
uiteindelijk veel overzichtelijker blijft, en bijgevolg, makkelijk uit te
+
62
breiden, te testen, te begrijpen, ...
+
63
+
64
Al deze voordelen graan grotendeels verloren als ik beslis om zelf
+
65
gespecialiseerde classes op te stellen.
+
66
Men kan misschien stellen dat "de voordelen die het schrijven van eigen
+
67
classes veel beter tegemoet komt aan de essentie van object-georiënteerd
+
68
programmeren, dan zich _beperken_ tot slechts een handvol generieke classes, die
+
69
misschien niet volledig aan de benodigdheden beantwoorden".
+
70
+
71
Toch laat ik mijn afweging overslaan in het voordeel van minder classes, en meer
+
72
uniformiteit. _Sometimes, less is more._ Meer classes betekent ook:
+
73
- Meer onderhoud
+
74
- Meer kans op bugs
+
75
- Groter programma
+
76
+
77
En al die problemen resulteren op lange termijn in:
+
78
- Slechtere uitbreidbaarheid
+
79
- Slechtere onderhoudbaarheid
+
80
- Slechtere schaalbaarheid
+
81
+
82
Zijn al die problemen de moeite van een (zogezegd) "beter object-georiënteerd
+
83
design" wel waard?
+
84
Veel mensen stellen juist dat OOP net voordelig is als men op zoek is naar
+
85
- Uitbreidbaarheid
+
86
- Onderhoudbaarheid
+
87
- Modulariteit
+
88
- Schaalbaarheid
+
89
+
90
Als de voordelen van het paradigma verdwijnen als ik dat "beter design" volg,
+
91
is dat design dan wel echt beter?
+
92
+
93
+
94
**Conclusie: Uniforme classes zijn volgens mij soms beter dan een stel
+
95
gespecialiseerde classes. Daarom dat ik mij soms behelp met Strings, intergers,
+
96
... i.p.v. zelf een oplossing te schrijven.**
+
97
+
98
+
99
### Null pointers
40
100
Het valt misschien op dat ik doorheen mijn programma in veel contracten eis dat
41
101
geen enkele parameter een zgn. *null pointer* is.
42
102
43
103
Het gebruik van null pointers staat garant voor een overvloed aan moeilijk te
44
104
vinden bugs die (door het design van objectgeörienteerd programmeren) enorm diep
45
105
kunnen doorpropageren.
46
106
47
107
Ik maak er een kerntaak van dat, als er aan mijn programma gewerkt wordt, de
48
108
programmeur zichzelf steeds kan garanderen dat **alle** data die hij
49
109
ontvangt, valide data is.
50
110
Op deze manier valt er een hele last van de schouders van de programmeur; een
51
111
reeks fouten worden voorkomen, simpelweg door een strikt schema aan te houden.
52
112
53
113
Het controleren op null pointers wordt op 2 manieren gedaan:
54
114
- Gebruik van *methods* aanwezig in het gegeven type. Als de gegeven variabele
55
115
  een null pointer is, zal het programma direct crashen, en een
56
116
  NullPointerException geven.
57
117
- Expliciet testen of *var == null*. Wordt toegepast op parameters die direct
58
118
  als members opgeslagen dienen te worden.
59
119
60
120
Deze (contractuele) controle laat toe dat, mocht er een null pointer gebruikt
61
121
worden, het programma de programmeur hiervan direct op de hoogte stelt, en dit
62
122
op het laagst mogelijke niveau (namelijk de eerste method waar deze waarde
63
123
gebruikt wordt).
64
124
65
125
### Cloning
66
126
members 'private' maken (encapsuleren) is volledig nutteloos als men getters en
67
127
setters op deze members toepast; In Java worden references doorgegeven (m.u.v.
68
128
primitives), die de hele notie van encapsulatie voorbijgaan (bij sommige types).
69
129
Een voorbeeld hiervan is het privatiseren van een Set<T>-member: men kan daar
70
130
een 'getSet()'-method op plaatsen, en dan toch de inhoud van deze 'private'
71
131
aanpassen.
72
132
73
133
Ik heb geopteerd om, waar van toepassing, deze variabelen te 'clonen', om zo
74
134
exacte kopieën terug te geven.
75
135
Deze manier van werken brengt enkele voordelen teweeg:
76
136
- Zeer defensief programmeren; De ontwikkelaar kan geen members aanpassen als
77
137
  dat niet de bedoeling was
78
138
- Duidelijkheid code: getSet().clear() zal de member niet meer leegmaken. Om dat
79
139
  te doen, moet men gebruikmaken van de method die daarvoor bedoeld is:
80
140
  setSet(clearedSet)
81
141
82
142
### Inheritance
83
143
Overerving is een goed concept over het algemeen, maar **niet** in OOP.
84
144
De problemen omtrent impliciet gedrag en onnodige *state* zijn al te vaak
85
145
beschreven met OOP-inheritance.
86
146
87
147
Ik heb in mijn programma geen gebruik gemaakt van inheritance, exact omwille van
88
148
de problemen die het voortbrengt, zeker in termen van herbruikbaarheid en
89
149
robuustheid, wat toch zware vereisten waren voor deze opdracht.
90
150
91
151
Ik heb al mijn problemen makkelijk kunnen oplossen d.m.v. compositie.
92
152
93
153
### Benaming variabelen
94
154
Doorheen mijn programma maak ik heel veel gebruik van dezelfde benamingen.
95
155
Bijvoorbeeld: Een variabele van het type Reservation zal haast altijd
96
156
'reservation' heten, een Set van een bepaald type zal de naam van datzelfde type
97
157
dragen, in het meervoud, ...
98
158
99
159
Sommige programmeurs gebruiken liever afkortingen (bv. 'reservation' -->
100
160
'resv'), omdat dit sneller schrijft.
101
161
102
162
Naar mijn mening moet men bij deze werkwijze inleveren aan leesbaarheid, vooral
103
163
wanneer iemand die nog nooit met de code gewerkt heeft, dit programma moet
104
164
overnemen.
105
165
106
166
Daarnaast zorgt de consistentie van woordgebruik ervoor dat een andere
107
167
programmeur, doorheen het hele programma dezelfde context in zijn/haar gedachten
108
168
kan gebruiken.
109
169
110
170
111
171
112
172
113
173
------------------------------------------------------------ TODO
114
174
## Toepassing types/classes
115
175
Doorheen het programma heb ik getracht zoveel mogelijk gebruik te maken van
116
176
types/classes die
117
177
- Veelvoorkomend zijn in de Java STL (Zoals String, Set, List, ...)
118
178
- primitief zijn (ints, ...), omdat deze operatoren hebben en de code
119
179
  leesbaarder maken
120
180
121
181
Een goed voorbeeld hiervan zijn bv. de faciliteiten:
122
182
I.p.v. een aparte "Facility"-class te maken, heb ik de verschillende
123
183
faciliteiten voorgesteld door een simpele String. De voordelen van deze aanpak
124
184
zijn ook direct duidelijk:
125
185
- Betekenis is direct duidelijk; de faciliteit letterlijk in de code vernoemd
126
186
- Makkelijke interactie met GUI, die sowieso Strings vraagt voor bv. JLabel
127
187
- Uitbreidbaarheid wordt bekomen door simpelweg een nieuwe String te
128
188
  introduceren
129
189
130
190
## View en GUI
131
191
Werken met GUI's is vaak tijdrovend en veroorzaakt snel errors, zeker met bv.
132
192
anonieme methods, exceptions, ...
133
193
Alhoewel mijn programma grotendeels in een MVC-stijl is geschreven, maken de
134
194
view-classes (RegistrationView, SearchView, ...) achterliggend gebruik van een
135
195
zelfgemaakt framework om makkelijk vensters te maken.
136
196
Dit kleine framework is een persoonlijk hobbyproject dat ik JSugar noem.
137
197
Het biedt een heleboel voordelen, vergeleken met elk GUI-venster zelf opstellen:
138
198
- Vaak gebruikte GUI-widgets (zoals een label, textfield) worden aangemaakt en
139
199
  toegevoegd door slechts 1 method op te roepen
140
200
- JSugar maakt gebruik van reflectie om op een leesbare en uitbreidbare manier
141
201
  knoppen te activeren:
142
202
  public JButton createButton(String text, String action, String methodName, Object triggerObject)
143
203
  'methodName' is een simpele String, en 'triggerObject' is het object waar deze
144
204
  method moet worden opgeroepen.
145
205
- Automatische uitlijning van widgets
146
206
Voor meer informatie kunt u JSugar-readme.md raadplegen.
147
207
148
208
## java.util.Date
149
209
150
210
Doorheen het programma maak ik vaak gebruik van de Date-class uit de Java STL,
151
211
om de volgende redenen:
152
212
- Uitbreidbaarheid: Door overal eenzelfde type te gebruiken, is het gemakkelijk
153
213
  om nieuwe modules toe te voegen, zonder dat daarvoor abstractielagen etc.
154
214
  nodig zijn.
155
215
- Uniformiteit: Eenzelfde type uit de STL laat de ontwikkelaar toe om door het
156
216
  hele programma heen hetzelfde denkpatroon aan te houden; een
157
217
  Stringvoorstelling hier, een integer daar, ... veroorzaken problemen en bugs,
158
218
  die met deze class voorkomen worden.
159
219
160
220
## Bedden
161
221
162
222
Ik heb voor bedden een aparte class aangemaakt, omdat deze een bepaalde state
163
223
bijhouden, nml. wanneer ze gereserveerd zijn.
164
224
165
225
166
226
## Reservation
167
227
Voor de reservaties heb ik besloten om enkel die data bij te houden die inherent
168
228
gerelateerd is aan die reservatie:
169
229
- Enkel gereserveerde bedden i.p.v. gereserveerde kamers. Qua uitbreidbaarheid
170
230
  heeft dit tot gevolg dat men gemakkelijk kan uitbreiden naar reservaties,
171
231
  gespreid over verschillende kamers.
172
232
173
233
174
234
## ReservationView
175
235
Merk op hoe in ReservationView de data van de Reservation direct in de GUI wordt
176
236
geplaatst.
177
237
Dit staat toe om zeer gemakkelijk deze class te hergebruiken voor zowel het
178
238
**aanmaken** als het **updaten** van de reservatie.
179
239