OOP2

ontwerpkeuzes.md

1
# Maarten Vangeneugden - 1438256
2
3
## GRASP
4
Om zoveel mogelijk tegemoet te komen aan de GRASP-richtlijnen, heb ik volgende
5
ontwerpkeuzes toegepast voor de verschillende richtlijnen.
6
7
### High cohesion & Low coupling
8
- Veel classes zijn totaal van elkaar losgekoppeld. Een goed voorbeeld hiervan
9
  is Bed; Bed weet niet over dat er Reservaties bestaan, zelfs niet in welke
10
  Room het 'staat'.
11
- Als er toch gekoppeld moet worden, dan blijft dit tot een minimum beperkt; Een
12
  Room weet wel welke Bedden het heeft, maar niet hoe deze gebruikt worden, een
13
  Reservation weet wel welke Bedden voor hem gereserveerd zijn, maar heeft geen
14
  weet van welke kamer dat deze staat.
15
- Uitzondering op deze regel vormen de Controller-classes; omwille van hun taken
16
  zijn deze vaak verplicht om van veel verschillende classes op de hoogte te
17
  zijn.
18
19
### Indirectie
20
- In plaats van functionaliteit toe te wijzen aan class X om met class Y te
21
  interageren, wordt er vaak gebruik gemaakt van een class Z, die deze
22
  verantwoordelijkheid op zich neemt.
23
- Dit wordt toegepast d.m.v. een MVC-structuur, waarin de \*Controller-classes
24
  als 'tussenpersoon' werken.
25
- Dit komt ook tegemoet aan de eigenschappen van Information Expertise.
26
27
### Creator
28
- Controllers staan ook in als zgn. Creators van de models die ze beheren. Ze
29
  voldoen dan ook aan de eigenschappen zoals
30
  [hier](https://en.wikipedia.org/wiki/GRASP_(object-oriented_design)#Creator)
31
  opgesomd wordt.
32
33
34
# Veranderingen t.o.v. Challenge 1
35
- Verkrijgen van een vrije kamer is verplaatst van ReservationView naar
36
  RoomController.
37
- Toevoeging van veel documentatie, vooral in de vorm van Javadoc, maar ook
38
  _inline commenting_ waar nodig/gewenst.
39
- Toevoeging van een systeem om wandelingen te organiseren (1 testwandeling als
40
  voorbeeld incluis).
41
- Nieuw zoekvenster, speciaal gericht op het behandelen van wandelingen.
42
- Zoekvensters zijn nu haast volledig operationeel, en geven bruikbare
43
  antwoorden en data terug.
44
- Eerder gemaakte reservaties/wandelreservaties kunnen later aangepast en/of
45
  verwijderd worden.
46
- Prijsberekening op orde gesteld.
47
- Toevoeging van een automatische _room generator_ in Main, om snel en met
48
  willekeurige data het programma te testen.
49
- Toepassing van contractueel programmeren in vele methods; vaak wordt de method
50
  nog niet uitgevoerd als het contract niet 100% wordt nageleefd.
51
52
### Vereiste aanpassingen
53
De aanpassingen die ik heb moeten doorvoeren om wandelingen toe te voegen, zijn
54
grotendeels beperkt gebleven tot de plekken in de code die sowieso van meerdere
55
onderdelen van het programma op de hoogte zijn;
56
Zo is er niks veranderd aan Reservation of Room, maar WalkController en
57
ReservationController hebben elkaar nu wel als member.
58
59
Aan de GUI-kant was het slechts 1 knopje toevoegen in het hoofdmenu.
60
61
Ik heb het zo opgesteld dat een groepsnaam die overeenkomt met een
62
hostelreservering, wordt aanzien als een reservering van dezelfde persoon.
63
Als de namen niet overeen komen, dan zijn het verschillende groepen.
64
65
Deze conventie laat mij toe om het programma veel beter te laten voldoen aan
66
high cohesion/low coupling, zonder daarvoor veel voordelen voor hoeven in te
67
leveren.
68
69
Ik was origineel van plan om de zoekfunctionaliteit bij het bestaande
70
zoekvenster te plaatsen, maar ik vond dat dat nogal onduidelijk ging worden. Ik
71
heb dus voor wandelmanagement een apart zoekvenster gemaakt, te bereiken vanuit
72
het hoofdmenu.
73
74
Uiteindelijk ben ik blij van de beperkte aanpassingen in het eerste gedeelte van
75
de challenge. Ik heb slechts hier en daar een extra member moeten toevoegen, en
76
het geheel is nog steeds degelijk gesplitst.
77
78
# Algemene keuzes ter bevordering codekwaliteit
79
80
## Strings, integers, ... i.p.v. Enums/Eigen classes
81
In het programma zijn er sommige members die doen vermoeden dat ze beter als
82
Enums aangeduid kunnen worden; Het type van een kamer, faciliteiten, ...
83
84
In plaats van een speciale class hiervoor te maken, heb ik gekozen om deze
85
gewoon te behandelen als simpele Strings in lijsten.
86
87
Het voordeel aan deze werkwijze, is dat Strings in Java SE quasi universeel
88
voorkomen; data kunnen geconverteerd worden naar Strings (en vice versa), veel
89
gebruikte GUI-libraries (waaronder Swing, JavaFX, ...) gebruiken Strings voor
90
tekst voor te stellen in de GUI-widgets, ...
91
Daarnaast weet iedereen die ook maar een beetje geschoold is in Java, direct hoe
92
deze members behandeld kunnen worden. Had ik een class gemaakt die bv.
93
RoomFacilities heette, dan is die parate kennis over de taal zelf nutteloos.
94
95
Strings zijn ook voorzien van extreem veel methods, en zijn dus zeer flexibele
96
classes om te gebruiken. Het feit dat ze zo makkelijk doorheen het programma te
97
gebruiken zijn is dus een groot pluspunt.
98
99
Als dat nog niet genoeg is: Het gebruiken van de hulpmiddelen uit de _standard
100
library_ is niet enkel waarvoor libraries überhaupt bestaan, het beperkt ook
101
het benodigde aantal classes in de eigen software, waardoor het geheel
102
uiteindelijk veel overzichtelijker blijft, en bijgevolg, makkelijk uit te
103
breiden, te testen, te begrijpen, ...
104
105
Al deze voordelen graan grotendeels verloren als ik beslis om zelf
106
gespecialiseerde classes op te stellen.
107
Men kan misschien stellen dat "de voordelen die het schrijven van eigen
108
classes veel beter tegemoet komt aan de essentie van object-georiënteerd
109
programmeren, dan zich _beperken_ tot slechts een handvol generieke classes, die
110
misschien niet volledig aan de benodigdheden beantwoorden".
111
112
Toch laat ik mijn afweging overslaan in het voordeel van minder classes, en meer
113
uniformiteit. _Sometimes, less is more._ Meer classes betekent ook:
114
- Meer onderhoud
115
- Meer kans op bugs
116
- Groter programma
117
118
En al die problemen resulteren op lange termijn in:
119
- Slechtere uitbreidbaarheid
120
- Slechtere onderhoudbaarheid
121
- Slechtere schaalbaarheid
122
123
Zijn al die problemen de moeite van een (zogezegd) "beter object-georiënteerd
124
design" wel waard?
125
Veel mensen stellen juist dat OOP net voordelig is als men op zoek is naar
126
- Uitbreidbaarheid
127
- Onderhoudbaarheid
128
- Modulariteit
129
- Schaalbaarheid
130
131
Als de voordelen van het paradigma verdwijnen als ik dat "beter design" volg,
132
is dat design dan wel echt beter?
133
134
135
**Conclusie: Uniforme classes zijn volgens mij soms beter dan een stel
136
gespecialiseerde classes. Daarom dat ik mij soms behelp met Strings, intergers,
137
... i.p.v. zelf een oplossing te schrijven.**
138
139
140
### Null pointers
141
Het valt misschien op dat ik doorheen mijn programma in veel contracten eis dat
142
geen enkele parameter een zgn. *null pointer* is.
143
144
Het gebruik van null pointers staat garant voor een overvloed aan moeilijk te
145
vinden bugs die (door het design van object-georienteerd programmeren) enorm diep
146
kunnen doorpropageren.
147
148
Ik maak er een kerntaak van dat, als er aan mijn programma gewerkt wordt, de
149
programmeur zichzelf steeds kan garanderen dat **alle** data die hij
150
ontvangt, valide data is, tenzij dat expliciet anders wordt aangegeven.
151
Op deze manier valt er een hele last van de schouders van de programmeur; een
152
reeks fouten worden voorkomen, simpelweg door een strikt schema aan te houden.
153
154
Het controleren op null pointers wordt op 2 manieren gedaan:
155
- Gebruik van *methods* aanwezig in het gegeven type. Als de gegeven variabele
156
  een null pointer is, zal het programma direct crashen, en een
157
  NullPointerException geven.
158
- Expliciet testen of *var == null*. Wordt toegepast op parameters die direct
159
  als members opgeslagen dienen te worden.
160
161
Een uitzondering op het vermijden van null pointers vormen sommige methods die
162
slechts 1 object teruggeven. In deze gevallen kan het voorvallen dat het te
163
zoeken object niet gevonden wordt. Om de ontwikkelaar hiervan op de hoogte te
164
stellen, wordt dan soms een null teruggestuurd.
165
Dit wordt steeds expliciet vermeld.
166
167
Deze (contractuele) controle laat toe dat, mocht er een null pointer gebruikt
168
worden, het programma de programmeur hiervan direct op de hoogte stelt, en dit
169
op het laagst mogelijke niveau (namelijk de eerste method waar deze waarde
170
gebruikt wordt).
171
172
### Cloning
173
members 'private' maken (encapsuleren) is volledig nutteloos als men getters en
174
setters op deze members toepast; In Java worden references doorgegeven (m.u.v.
175
primitives), die de hele notie van encapsulatie voorbijgaan (bij sommige types).
176
Een voorbeeld hiervan is het privatiseren van een Set<T>-member: men kan daar
177
een 'getSet()'-method op plaatsen, en dan toch de inhoud van deze 'private'
178
aanpassen.
179
180
Ik heb geopteerd om, waar van toepassing, deze variabelen te 'clonen', om zo
181
exacte kopieën terug te geven.
182
Deze manier van werken brengt enkele voordelen teweeg:
183
- Zeer defensief programmeren; De ontwikkelaar kan geen members aanpassen als
184
  dat niet de bedoeling was
185
- Duidelijkheid code: getSet().clear() zal de member niet meer leegmaken. Om dat
186
  te doen, moet men gebruikmaken van de method die daarvoor bedoeld is:
187
  setSet(clearedSet)
188
189
### Inheritance
190
Overerving is een goed concept over het algemeen, maar **niet** in OOP.
191
De problemen omtrent impliciet gedrag en onnodige *state* zijn al te vaak
192
beschreven met OOP-inheritance.
193
194
Ik heb in mijn programma geen gebruik gemaakt van inheritance, exact omwille van
195
de problemen die het voortbrengt, zeker in termen van herbruikbaarheid en
196
robuustheid, wat toch zware vereisten waren voor deze opdracht.
197
198
Ik heb al mijn problemen makkelijk kunnen oplossen d.m.v. compositie.
199
200
### Benaming variabelen
201
Doorheen mijn programma maak ik heel veel gebruik van dezelfde benamingen.
202
Bijvoorbeeld: Een variabele van het type Reservation zal haast altijd
203
'reservation' heten, een Set van een bepaald type zal de naam van datzelfde type
204
dragen, in het meervoud, ...
205
206
Sommige programmeurs gebruiken liever afkortingen (bv. 'reservation' -->
207
'resv'), omdat dit sneller schrijft.
208
209
Naar mijn mening moet men bij deze werkwijze inleveren aan leesbaarheid, vooral
210
wanneer iemand die nog nooit met de code gewerkt heeft, dit programma moet
211
overnemen.
212
213
Daarnaast zorgt de consistentie van woordgebruik ervoor dat een andere
214
programmeur, doorheen het hele programma dezelfde context in zijn/haar gedachten
215
kan gebruiken.
216
217
Nu, ik maak hier soms een uitzondering op, omdat het soms zo lang wordt dat de
218
code in zijn geheel moeilijker leesbaar wordt.
219
Een voorbeeld van hoe dit uitmondt is Objective-C. Haast **alles** wordt voluit
220
genoteerd, waardoor van de eigenlijke essentie van het programma haast niks
221
overblijft.
222
223
De controllers heb ik daarom in sommige gevallen toch tot hun initialen
224
afgekort. Ik vond dat het verlies aan expressiviteit meer dan goed gemaakt werd
225
door het winnen aan leesbaarheid.
226
227
228
## Toepassing types/classes
229
Doorheen het programma heb ik getracht zoveel mogelijk gebruik te maken van
230
types/classes die
231
- Veelvoorkomend zijn in de Java STL (Zoals String, Set, List, ...)
232
- primitief zijn (ints, ...), omdat deze operatoren hebben en de code
233
  leesbaarder maken
234
235
Een goed voorbeeld hiervan zijn bv. de faciliteiten:
236
I.p.v. een aparte "Facility"-class te maken, heb ik de verschillende
237
faciliteiten voorgesteld door een simpele String. De voordelen van deze aanpak
238
zijn ook direct duidelijk:
239
- Betekenis is direct duidelijk; de faciliteit letterlijk in de code vernoemd
240
- Makkelijke interactie met GUI, die sowieso Strings vraagt voor bv. JLabel
241
- Uitbreidbaarheid wordt bekomen door simpelweg een nieuwe String te
242
  introduceren
243
244
## View en GUI
245
Werken met GUI's is vaak tijdrovend en veroorzaakt snel errors, zeker met bv.
246
anonieme methods, exceptions, ...
247
Alhoewel mijn programma grotendeels in een MVC-stijl is geschreven, maken de
248
view-classes (RegistrationView, SearchView, ...) achterliggend gebruik van een
249
zelfgemaakt framework om makkelijk vensters te maken.
250
Dit kleine framework is een persoonlijk hobbyproject dat ik JSugar noem.
251
Het biedt een heleboel voordelen, vergeleken met elk GUI-venster zelf opstellen:
252
- Vaak gebruikte GUI-widgets (zoals een label, textfield) worden aangemaakt en
253
  toegevoegd door slechts 1 method op te roepen
254
- JSugar maakt gebruik van reflectie om op een leesbare en uitbreidbare manier
255
  knoppen te activeren:
256
  public JButton createButton(String text, String action, String methodName, Object triggerObject)
257
  'methodName' is een simpele String, en 'triggerObject' is het object waar deze
258
  method moet worden opgeroepen.
259
- Automatische uitlijning van widgets middels de standaard FlowLayout
260
Voor meer informatie kunt u JSugar-readme.md raadplegen.
261
262
## java.util.Date
263
264
Doorheen het programma maak ik vaak gebruik van de Date-class uit de Java STL,
265
om de volgende redenen:
266
- Uitbreidbaarheid: Door overal eenzelfde type te gebruiken, is het gemakkelijk
267
  om nieuwe modules toe te voegen, zonder dat daarvoor abstractielagen etc.
268
  nodig zijn.
269
- Uniformiteit: Eenzelfde type uit de STL laat de ontwikkelaar toe om door het
270
  hele programma heen hetzelfde denkpatroon aan te houden; een
271
  Stringvoorstelling hier, een integer daar, ... veroorzaken problemen en bugs,
272
  die met deze class voorkomen worden.
273
274
De datavelden in de GUI komen altijd met de huidige datum op het veld genoteerd.
275
Geef data in in hetzelfde formaat, en de achtergrond doet de rest.
276
277
### Deprecation
278
Ik besef dat ik in java.util.Date veel gebruik maak van _deprecated methods_.
279
Nu, deze methods bieden mij wel de kans om snel en gemakkelijk met data om te
280
kunnen gaan.
281
Zeker het tijdsgebrek dat komt kijken bij de challenges zorgen ervoor dat ik
282
mijn niet de luxe kan veroorloven om een speciaal voor mij gemaakte dataclass te
283
maken.
284
285
### Ontbijtdata
286
287
Het moeilijkste om te implementeren waren de data voor ontbijt.
288
Er wordt voor de reservaties steeds een set bijgehouden van de data waarop
289
ontbijt besteld is.
290
Op zich is dit niet zo moeilijk. Het moeilijke hieraan, is de gebruiker van het
291
programma op een begrijpelijke manier deze data te laten invoeren.
292
Data worden ingevoerd via tekstvelden, omdat Swing geen zgn. "DatePicker" heeft.
293
294
Ontbijt wordt doorheen het programma geserveerd om 9 uur.
295
296
297
### GUI
298
299
Swing biedt geen widget die zich specialiseert in het weergeven van informatie
300
over een datum (een zgn. _calendar widget_).
301
302
In de opdracht stond dat we geen "visueel aantrekkelijke GUI" hoeven te
303
ontwerpen, maar wel een die "alle functionaliteit ondersteunt".
304
305
Wegens het tijdsgebrek en de tekortkoming van Swing, heb ik besloten om data
306
weer te geven in een simpel JTextField.
307
Het biedt de beste oplossing voor wat gevraagd wordt in deze opdracht, en wegens
308
de tijdslimiet tijdens de challenges zelf vormen ze een goede
309
"kortetermijnoplossing".
310
311
## Bedden
312
313
Ik heb voor bedden een aparte class aangemaakt, omdat deze een bepaalde state
314
bijhouden, nml. wanneer ze gereserveerd zijn.
315
316
317
## Reservation
318
Voor de reservaties heb ik besloten om enkel die data bij te houden die inherent
319
gerelateerd is aan die reservatie:
320
- Enkel gereserveerde bedden i.p.v. gereserveerde kamers. Qua uitbreidbaarheid
321
  heeft dit tot gevolg dat men gemakkelijk kan uitbreiden naar reservaties,
322
  gespreid over verschillende kamers.
323
324
325
## ReservationView / WalkView
326
Merk op hoe in ReservationView de data van de Reservation direct in de GUI wordt
327
geplaatst.
328
Dit staat toe om zeer gemakkelijk deze class te hergebruiken voor zowel het
329
**aanmaken** als het **updaten** van de reservatie.
330
331
Dezelfde werkwijze wordt toegepast ook WalkView.
332
333
334
## Opmerkingen
335
336
- Door het gebruik van de FlowLayout in de GUI, is het mogelijk dat sommige
337
  gedeelten van de GUI niet direct worden weergegeven, daar ze verborgen worden
338
  door de hoogte van het venster. Men kan deze tevoorschijn halen door zelf het
339
  venster in de hoogte te verstellen.
340