OOP2

Improved the Bed class of Challenge 6 substiantially; it's completely decoupled from the rest of the program, filled with documentation, ... In a nutshell: You won't find any better OOP application that this.

Author
Maarten 'Vngngdn' Vangeneugden
Date
Nov. 23, 2016, 10:03 p.m.
Hash
7592b73b42ce858ed5d466a98e15effd5f24dd1c
Parent
cad9fd0c2e21c33a85d25b5ab02f0ced24ae48f5
Modified file
Challenge 6/Bed.java

Challenge 6/Bed.java

115 additions and 9 deletions.

View changes Hide changes
1
1
import java.util.Set;
2
-
+
2
import java.util.HashMap;
+
3
3
4
public class Bed {
+
5
 * Class representing a bed in the hostel.
+
6
 * Even though beds in a hostel could simply be an integer in a Room, these Beds
+
7
 * need to remember on what dates they are reserved.
+
8
 * @author Maarten Vangeneugden - 1438256
+
9
 */
+
10
public class Bed {
4
11
5
12
	private Set<Date> reservedDates;
6
-
+
13
	 * I know that a mapping is not necessarily the best solution for storing
+
14
	 * periods, because it doesn't offer built-in protection yadda yadda.
+
15
	 * However, that's Java's fault, as it doesn't provide a Pair<L,R> thing in
+
16
	 * the STL.
+
17
	 * The best solution is actually a collection of tuples: (Begin, End), but
+
18
	 * that doesn't exist in Java, and thus requires a custom implementation.
+
19
	 * All things considered, a Map is the least bad choice.
+
20
	 */
+
21
	private Map<Date, Date> reservedPeriods;
+
22
7
23
	public Bed(Set<Date> reservedDates) {
8
-
		this.reservedDates = reservedDates;
9
-
	}
+
24
		this.reservedPeriods = new HashMap<>();
+
25
	}
10
26
11
27
	/**
+
28
	 * Reserves this Bed for the given period.
+
29
	 * This method will mark the given period for this Bed as "reserved", which
+
30
	 * can then be cancelled or queried later.
+
31
	 * @param begin The time where the reservation begins.
+
32
	 * @param end The time where the reservation ends.
+
33
	 * @pre No parameter may be a null pointer.
+
34
	 * @pre The given period mustn't overlap with a period already marked as
+
35
	 * reserved.
+
36
	 * @pre begin must come before end.
+
37
	 * @pre begin and end mustn't be equal.
+
38
	 * @post The given period will be marked as "Reserved", and will have to be
+
39
	 * manually cancelled/removed in order to reserve again.
+
40
	 * @throws NullPointerException if any parameter is a null pointer.
+
41
	 * @throws IllegalArgumentException if begin is equal to, or comes after
+
42
	 * end.
+
43
	 * @throws DateTimeException if the given period overlaps with an already
+
44
	 * reserved period.
+
45
	 */
+
46
	public void reservePeriod(Date begin, Date end) {
+
47
		if(!begin.before(end)) {
+
48
			throw IllegalArgumentException("The begin date occurs after the end date.");
+
49
		}
+
50
		if(!this.isFree(begin, end)) {
+
51
			throw DateTimeException("This period overlaps with a reserved period.");
+
52
		}
+
53
		// Contract validated, execute method
+
54
		this.reservedPeriods.put(begin, end);
+
55
	}
+
56
+
57
	/**
+
58
	 * Remove a previous registration from this Bed.
+
59
	 * This method will remove/cancel the given reservation period from the
+
60
	 * Bed, opening it up for reservation again.
+
61
	 * @param begin The time where the reservation begins.
+
62
	 * @param end The time where the reservation ends.
+
63
	 * @pre No parameter may be a null pointer.
+
64
	 * @pre The given period must already be marked as "Reserved" in this Bed.
+
65
	 * @pre begin must come before end.
+
66
	 * @pre begin and end mustn't be equal.
+
67
	 * @post The given period will lose its "Reserved" mark, allowing the period
+
68
	 * to be reserved again.
+
69
	 * @throws NullPointerException if any parameter is a null pointer.
+
70
	 * @throws IllegalArgumentException if begin is equal to, or comes after
+
71
	 * end; or, if the given period is not reserved.
+
72
	 */
+
73
	public void removeReservationPeriod(Date begin, Date end) {
+
74
		if(!begin.before(end)) {
+
75
			throw IllegalArgumentException("The begin date occurs after the end date.");
+
76
		}
+
77
		if(!this.isFree(begin, end)) {
+
78
			throw DateTimeException("This period overlaps with a reserved period.");
+
79
		}
+
80
		// Contract partially validated; further validation occurs while looking
+
81
		// for the reservation.
+
82
		// XXX: Check if Java correctly handles equality: 2 different Date
+
83
		// objects with the same date representation should be equal!
+
84
		boolean reservationFound = this.reservedPeriods.remove(begin, end);
+
85
		if(!reservationFound) {
+
86
			throw IllegalArgumentException("The given period was not marked as reserved.");
+
87
		}
+
88
	}
+
89
		
+
90
	/**
12
91
	 * Checks whether this Bed can be reserved in the given period.
13
92
	 * @return True if it's free, false otherwise.
14
-
	 */
+
93
	 * conflicting reservation period.
+
94
	 * @param begin The time where the reservation begins.
+
95
	 * @param end The time where the reservation ends.
+
96
	 * @pre No parameter must be a null pointer.
+
97
	 * @pre begin must come before end.
+
98
	 * @pre begin and end mustn't be equal.
+
99
	 * @throws NullPointerException if any parameter is a null pointer.
+
100
	 * @throws IllegalArgumentException if begin is equal to, or comes after
+
101
	 * end.
+
102
	 * @return True if the given period does not overlap with any reservation, false otherwise.
+
103
	 */
15
104
	public boolean isFree(Date begin, Date end) {
16
105
		for(Date reservedDate: this.reservedDates) {
17
-
			if(reservedDate.after(begin) && reservedDate.before(end)) {
18
-
				return false;
+
106
			throw IllegalArgumentException("The begin date occurs after the end date.");
+
107
		}
+
108
		if(!this.isFree(begin, end)) {
+
109
			throw DateTimeException("This period overlaps with a reserved period.");
+
110
		}
+
111
		// Contract validated, execute method
+
112
		for(Map.Entry<Date, Date> reservedPeriod: this.reservedPeriods.EntrySet()) {
+
113
			Date reservedBegin = reservedPeriod.key();
+
114
			Date reservedEnd = reservedPeriod.value();
+
115
			/* Forbidden possibilities:
+
116
			 * (A,B = reserved; X,Y = requested)
+
117
			 * X-A-Y-B / A-X-B-Y  -  Begins or ends in a reserved period
+
118
			 * X-A-B-Y  -  Complete overlapping of reserved period
+
119
			 * Allowed possibilities:
+
120
			 * A-B-X-Y / X-Y-A-B  -  No overlapping
+
121
			 */
+
122
			if((begin.after(reservedBegin) && begin.before(reservedEnd)) ||
+
123
			   (end.after(reservedBegin) && end.before(reservedEnd))) {
+
124
				// Triggered if any forbidden structure is detected
+
125
				return false;
19
126
			}
20
127
		}
21
128
		return true;
22
-
	}
+
129
	}
23
130
		
24
-
}
25
131