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 |