Stel ik heb de volgende klasse:
Ik heb dus de klasse Dossier waarmee van alles gedaan kan worden. Bijvoorbeeld door een Business Laag. Zo kan dit dossier worden afgesloten. Daar hangt wel een aantal voorwaarden aan. Daarom wordt eerst gekeken of het dossier wel afgesloten kan worden:
Er wordt dus eerst gevraagd of het dossier zichzelf mag afsluiten. Want als er bijvoorbeeld nog geen handtekening van een bepaald persoon is gezet, of het bedrag overschrijdt een bepaalde limiet, of het is nog niet behandeld door de juiste afdeling (en ga zo maar door) dan mag het dossier zichzelf niet afsluiten.
CanAfluisten zou er bijvoorbeeld zo uitzien:
Maar dat is niet handig!
Want het dossier ( en dus ook de aanroepende code) weet nu alleen maar dat er niet afgesloten mag worden, maar niet waarom.
Er is een aantal oplossingen voor dit probleem:
Optie 1. Ik kan CanAfsluiten exceptions laten throwen waarin staat waarom het niet mag:
Deze oplossing vind ik niet mooi. Ik heb ooit geleerd dat je alleen excepties gebruikt als dingen niet goed gaan of bij onverwacht resultaat. Bovenstaande voorbeeld gaat echter perfect volgens verwachting. Zie het volgende voorbeeld:
Als ik record 1, 2 en 3 heb ik de database en ik zoek naar record 4, dan vind ik niks, precies zoals ik had verwacht. Ik krijg dus geen "NoRecordsFoundException" maar netjes 0 terug of een lege dataset of -row.
Dus als ik een dossier wil afsluiten terwijl er geen handtekening is, dan verwacht ik dat ik het dossier niet mag afsluiten.
Bovendien verdient het geen schoonheidsprijs als ik een boolean gebruik die alleen maar true teruggeeft. De false waarde treedt nooit op omdat er een exception wordt gegooid.
Optie 2:. Ik kan CanAfsluiten een string laten retourneren waarin staat waarom het niet mag:
Deze optie is al een stuk netter vind ik. Punt is alleen dat de aanroepende code een soort alternatieve errorhandling moet gaan maken om met deze berichten om te gaan.
Hoe gaan jullie met dit soort zaken om? En welke opties zijn er nog meer?
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
| |-----------------| | Dossier | |-----------------| | - Handtekening | | - Bedrag | | + CanAfsluiten | | + IsAfgesloten | |-----------------| | + Aanmaken | | + Fiatteren | | + Doorsturen | | + Afsluiten | |-----------------| |
Ik heb dus de klasse Dossier waarmee van alles gedaan kan worden. Bijvoorbeeld door een Business Laag. Zo kan dit dossier worden afgesloten. Daar hangt wel een aantal voorwaarden aan. Daarom wordt eerst gekeken of het dossier wel afgesloten kan worden:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| public void Afsluiten() { if ( CanAfsluiten ) { DoeDit(); DoeDat(); DoeZus(); DoeZo(); } else { //return "Afsluiten niet toegestaan, want ..."; } } |
Er wordt dus eerst gevraagd of het dossier zichzelf mag afsluiten. Want als er bijvoorbeeld nog geen handtekening van een bepaald persoon is gezet, of het bedrag overschrijdt een bepaalde limiet, of het is nog niet behandeld door de juiste afdeling (en ga zo maar door) dan mag het dossier zichzelf niet afsluiten.
CanAfluisten zou er bijvoorbeeld zo uitzien:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| public bool CanAfsluiten() { if ( Handtekening == null ) { return false; } if ( Bedrag > 100000 ) { return false; } ... ... else { return true; } } |
Maar dat is niet handig!
Want het dossier ( en dus ook de aanroepende code) weet nu alleen maar dat er niet afgesloten mag worden, maar niet waarom.
Er is een aantal oplossingen voor dit probleem:
Optie 1. Ik kan CanAfsluiten exceptions laten throwen waarin staat waarom het niet mag:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| public bool CanAfsluiten() { if ( Handtekening == null ) { throw new Exception("Er is nog geen handtekening gezet"); } if ( Bedrag >= 100000 ) { throw new Exception("Het bedrag moet lager dan 100000 zijn"); } ... ... else { return true; } } |
Deze oplossing vind ik niet mooi. Ik heb ooit geleerd dat je alleen excepties gebruikt als dingen niet goed gaan of bij onverwacht resultaat. Bovenstaande voorbeeld gaat echter perfect volgens verwachting. Zie het volgende voorbeeld:
Als ik record 1, 2 en 3 heb ik de database en ik zoek naar record 4, dan vind ik niks, precies zoals ik had verwacht. Ik krijg dus geen "NoRecordsFoundException" maar netjes 0 terug of een lege dataset of -row.
Dus als ik een dossier wil afsluiten terwijl er geen handtekening is, dan verwacht ik dat ik het dossier niet mag afsluiten.
Bovendien verdient het geen schoonheidsprijs als ik een boolean gebruik die alleen maar true teruggeeft. De false waarde treedt nooit op omdat er een exception wordt gegooid.
Optie 2:. Ik kan CanAfsluiten een string laten retourneren waarin staat waarom het niet mag:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| public string CanAfsluiten() { if ( Handtekening == null ) { return "Mag niet omdat er nog geen handtekening is gezet"; } if ( Bedrag > 100000 ) { return "Mag niet omdat het bedrag te hoog is"; } ... ... else { return ""; } } |
Deze optie is al een stuk netter vind ik. Punt is alleen dat de aanroepende code een soort alternatieve errorhandling moet gaan maken om met deze berichten om te gaan.
Hoe gaan jullie met dit soort zaken om? En welke opties zijn er nog meer?