[JAVA] Alternatieve aanpakken verplichte velden in class *

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
Woord vooraf: Ik heb geen gerelateerde posts op het forum gevonden, en een zoektocht op internet leid niet naar de juiste resultaten (of ik kan niet meer met Google omgaan, :'( ).

Mijn probleem is als volgt. Ik ben op het moment bezig om het werken met een bepaald systeem eenvoudiger te maken. Bij dat systeem kun je bepaalde modules / componenten aanmaken, waarbij je een X-aantal velden (class variables, om verwarring te voorkomen) in een object in moet stellen (tot wel 10 stuks).

Het probleem hierbij is echter dat, als je een veld niet of niet goed invult, je pas een fout krijgt als je de module probeert te installeren.

In een (mijns insziens) optimale situatie zou je gelijk bij het compilen van je programma al fouten moeten zien, zodat ze ook in een IDE verschijnen.

De enige aanpak die ik op dit moment weet is om de verplichte velden aan te merken als Final en alleen te initialiseren in een constructor (de taal is Java overigens). Echter, voor die classes die wel 10 velden nodig hebben wordt dit nogal onoverzichtelijk.

Dus hier is mijn vraag: Zijn er nog andere methodes bekend om verplichte velden tijdens compile-time te controleren? Of zijn er trucs om te kijken of bepaalde methodes wel aangeroepen worden?

Ik ben ook wel bekend met het Builder-pattern, die niet zo lang geleden langskwam, om lange aanroepen op een constructor overzichtelijker te maken, maar die controleert niet tijdens compile-time of al die setter functies wel aangeroepen worden. Het liefst zou de controle tijdens compilen moeten verlopen, dwz, dat de code niet compileert wanneer een veld niet ingesteld is.

Het alternatief, wat ik overigens nu ook al heb, is gewoon goede foutmeldingen te laten zien, maar ook dan krijg je nog gewoon een lijst exceptions voor je kiezen.

Dus, heeft er iemand nog ideeën?

Edit: een andere aanpak zou het opdelen van de grote class z'n verplichte velden in kleinere classes die wel allemaal met final velden werken, en die dan doorgeven aan de grote class, ook als final eigenschappen.

[ Voor 5% gewijzigd door YopY op 23-02-2009 11:03 . Reden: Kleine toevoeging / ideetje. ]


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 16:35
Moeilijk om hier goed op te antwoorden, aangezien de situatie niet echt gekend is, maar waarom maak je geen constructor die alle nodige velden als argument neemt (en geen default constructor voorzien)
Dan kan je al enkel maar dat object instantieren door die constructor te gebruiken, waarbij je alle fields initialiseert ?

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
whoami schreef op maandag 23 februari 2009 @ 11:10:
Moeilijk om hier goed op te antwoorden, aangezien de situatie niet echt gekend is, maar waarom maak je geen constructor die alle nodige velden als argument neemt (en geen default constructor voorzien)
Dan kan je al enkel maar dat object instantieren door die constructor te gebruiken, waarbij je alle fields initialiseert ?
Ik dacht dat ik die optie meenam in mijn fipo, maar het kan zijn dat die oplossing een beetje verzopen is. Die oplossing werkt wel, echter omdat de class die geïnstantieerd moet worden tot wel 10 of meer velden nodig heeft, kan de aanroep tot deze constructor nogal lang en onoverzichtelijk worden. De oplossing werkt wel en is zelfs de standaard, maar het maakt de code er niet echt leesbaarder op - je ziet namelijk snel door de bomen het bos niet meer, dwz, in de originele heb je een setName, setDescription, setXYZ functie waarvan je gelijk weet wat je instelt, maar bij een constructor met 10 params raak je dit overzicht heel snel kwijt.

Acties:
  • 0 Henk 'm!

  • Evilbee
  • Registratie: November 2002
  • Laatst online: 12:48
YopY schreef op maandag 23 februari 2009 @ 11:27:
[...]
De oplossing werkt wel en is zelfs de standaard, maar het maakt de code er niet echt leesbaarder op - je ziet namelijk snel door de bomen het bos niet meer, dwz, in de originele heb je een setName, setDescription, setXYZ functie waarvan je gelijk weet wat je instelt, maar bij een constructor met 10 params raak je dit overzicht heel snel kwijt.
Maar daar heb je toch documentatie (javaDoc) voor?

LinkedIn - Collega worden?


Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
Evilbee schreef op maandag 23 februari 2009 @ 11:45:
[...]

Maar daar heb je toch documentatie (javaDoc) voor?
Da's ook waar, maar dan moet je die er wel precies bij hebben. Goed leesbare code is, tenminste mijns insziens, een combinatie van goed commentaar, maar ook van intuitieve code. Een lijst met setX, setY, setZ is bijna zelf-beschrijvend, in tegenstelling tot een lijst argumenten met commentaar ergens anders.

Maar oké, je punt is wel geldig.

Acties:
  • 0 Henk 'm!

  • Orphix
  • Registratie: Februari 2000
  • Niet online
Abstract getter/setter methods?

Acties:
  • 0 Henk 'm!

  • TheNameless
  • Registratie: September 2001
  • Laatst online: 07-02 21:38

TheNameless

Jazzballet is vet!

Ik neem aan dat je je "module"s ergens opslaat? (database of xml whatever).
Kan je niet gewoon voordat je die module opslaat de boel valideren of alles is ingevuld? (bijvoorbeeld door een Validate() methode aan je modules toe te voegen)

Wat is er trouwens op tegen om een constructor te bouwen met een hoop variabelen?
Als logisch gezien al die variabelen nodig zijn om een valide object te krijgen, so be it. Daar is een constructor voor IMHO.

Ducati: making mechanics out of riders since 1946


Acties:
  • 0 Henk 'm!

  • Kettrick
  • Registratie: Augustus 2000
  • Laatst online: 10:22

Kettrick

Rantmeister!

Je zou kunnen overwegen om voor een dergelijk modulair systeem spring te gaan gebruiken. Hoewel dit niet compile-time werkt kan je met een @Required annotation redelijk makkelijk checken of je context in orde is, je weet het dan iig. tijdens het opstarten van je applicatie en krijgt geen NPE als iets niet geset is.

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
quote: Orphix
Abstract getter/setter methods?
Hoe bedoel je dit precies? Je forceert daar subclasses wel mee om die te implementeren, maar niet om te gebruiken, :/.
quote: TheNameless
Ik neem aan dat je je "module"s ergens opslaat? (database of xml whatever).
Deze 'modules' zijn gewoon Java programma's / modules, als OSGI je iets zegt dan is dat het.
quote: TheNameless
Kan je niet gewoon voordat je die module opslaat de boel valideren of alles is ingevuld? (bijvoorbeeld door een Validate() methode aan je modules toe te voegen)
Die optie heb ik op het moment ook, deze moet ik nog even verder uitwerken zodat 'ie exceptions gooit ipv gewoon (log)meldingen in de console.
quote: RoeLz
Je zou kunnen overwegen om voor een dergelijk modulair systeem spring te gaan gebruiken. Hoewel dit niet compile-time werkt kan je met een @Required annotation redelijk makkelijk checken of je context in orde is, je weet het dan iig. tijdens het opstarten van je applicatie en krijgt geen NPE als iets niet geset is.
Als het goed is, is de applicatie waar ik nu mee werk ook (in ieder geval deels) op Spring gebaseerd. Het opstarten van een module gebeurt alleen (helaas) niet dmv Spring, maar ik wil ook nog eens kijken of dit mogelijk is. Kun je @Required ook gebruiken zonder dat Spring het object aanmaakt / initialiseert? Kijk ik nog wel even naar, thanks.
quote: RoeLz
tijdens het opstarten van je applicatie en krijgt geen NPE als iets niet geset is.
Kreeg ik maar NPE's, dat wist ik wat het probleem was :+. Nee, als je iets niet invult in dit systeem krijg je RemoteMethodInvocation exceptions (oid, iets uit Java's Reflection API), zonder ook maar enige hint naar dat je - bijvoorbeeld - de naam van je module niet ingevuld hebt.

  • Kettrick
  • Registratie: Augustus 2000
  • Laatst online: 10:22

Kettrick

Rantmeister!

YopY schreef op donderdag 26 februari 2009 @ 09:12:
[...]

Als het goed is, is de applicatie waar ik nu mee werk ook (in ieder geval deels) op Spring gebaseerd. Het opstarten van een module gebeurt alleen (helaas) niet dmv Spring, maar ik wil ook nog eens kijken of dit mogelijk is. Kun je @Required ook gebruiken zonder dat Spring het object aanmaakt / initialiseert? Kijk ik nog wel even naar, thanks.
@Required werkt alleen als je beans door spring aangemaakt worden, mogelijk kan je het aanmaken van modules springmanaged maken door zelf een beanfactory te schrijven ?. Als ik me niet vergis kan je dan ook gebruik maken van de @Required annotation.
Kreeg ik maar NPE's, dat wist ik wat het probleem was :+. Nee, als je iets niet invult in dit systeem krijg je RemoteMethodInvocation exceptions (oid, iets uit Java's Reflection API), zonder ook maar enige hint naar dat je - bijvoorbeeld - de naam van je module niet ingevuld hebt.
Sterkte :') :w

  • Appesteijn
  • Registratie: Juni 2001
  • Niet online
Begrijp ik het goed dat je niet verder wilt als die waardes null zijn? Dan kan je toch in je constructor op deze velden check en een (eigen) Exceptie gooien? Dan kan de gebruiker in ieder geval niet verder zonder deze waardes in te vullen.

  • alx
  • Registratie: Maart 2002
  • Niet online

alx

YopY schreef op donderdag 26 februari 2009 @ 09:12:
[...]
Hoe bedoel je dit precies? Je forceert daar subclasses wel mee om die te implementeren, maar niet om te gebruiken, :/.
En als je die methodes die geimplementeerd moeten worden aanroept vanuit de abstract class? Moet je alleen nog zorgen dat die methode in de abstract class altijd aangeroepen wordt als er een object van de subclass wordt geinstantieerd. Mss kun je dat met de constructor of een static block voor elkaar krijgen. Of iets anders creatiefs.

@Appesteijn e.a.: Nee, hij wil het @compile-time checken, niet @run-time.

[ Voor 6% gewijzigd door alx op 26-02-2009 09:45 ]


Verwijderd

@compile-time checken of een public methode is aangeroepen, denk niet dat het kan.
Heb nog even gekeken of het kan met een zelf gemaakte Annotation maar ook zonder succes.

Ik heb nog geen goed argument gehoord waarom het niet in de constructor kan. Dat de code onoverzichtelijk wordt is onzin. Desnoods breek je je klasse maar op in meerdere klasse met een overkoepelende klasse.

Bij je validate methode zou je assertions kunnen gebruiken.

Nog een ander alternatief is default values.

[ Voor 7% gewijzigd door Verwijderd op 26-02-2009 14:28 ]


  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
Begrijp ik het goed dat je niet verder wilt als die waardes null zijn? Dan kan je toch in je constructor op deze velden check en een (eigen) Exceptie gooien? Dan kan de gebruiker in ieder geval niet verder zonder deze waardes in te vullen.
Dat sowieso, maar ik wil meer forceren dat bepaalde waardes altijd ingesteld worden. De velden als final declareren en in de constructor instellen is tot nog toe de beste oplossing, maar dan krijg je in dit geval een nogal grote constructor, wat de gebruiksvriendelijkheid niet echt ten goede komt. Oke, Reflection excepties zijn ook niet echt gebruiksvriendelijk.

Op het moment steven ik af op het verder onderverdelen in componenten van het component, zodat ik uiteindelijk maar een handjevol (max 5) params door hoef te geven aan de constructor. De verschillende waardes zijn wel in categorieen onder te verdelen, dus dat moet op zich geen probleem zijn.
quote: Khainer
Ik heb nog geen goed argument gehoord waarom het niet in de constructor kan. Dat de code onoverzichtelijk wordt is onzin. Desnoods breek je je klasse maar op in meerdere klasse met een overkoepelende klasse.
Daar lijkt het wel op af te stevenen, ja. Kon zijn dat iemand nog een slim idee had of dat er een feature in Java was waar ik niet mee bekend was, maar het lijkt er niet op, :/. Het enige echte argument waarom het niet in de constructor kan is eigenlijk meer persoonlijk - je hebt op het moment 'zelf-beschrijvende' code, waar je de functionaliteit af kan leiden uit de setter naam (setName, setId, setHuppelepup, noem maar op), maar dat raak je kwijt met een constructor (dan moet je de commentaren lezen, content assist gebruiken, etc). Kan ook wel, maar dan moeten er weer minder stukken gegevens komen (vindt ik persoonlijk, maar ik ben een muggezifter).

Heb al een hele mooie abstractie gemaakt (al zeg ik het zelf) voor een bepaald onderdeel van een component definitie, de toegangsregels (permissions) zijn nu allemaal ondergebracht in een enkel object. Die zou sowieso in de constructor toegekend kunnen worden.

Verder kan een aantal strings (naam, ID, beschrijving) in een eigen object ondergebracht worden, is er een verzameling class namen die ook in een eigen object kunnen, etc. Moet wel lukken uiteindelijk.

Default waardes moet er ook nodig in, heb ik sowieso al voor die permissions die, in de basis, geimplementeerd worden als een stel Strings (bah), maar die met mijn zooi automagisch gegenereerd worden aan de hand van standaardwaardes en aannames. Er zijn nog een paar andere velden die ook standaard kunnen zijn, maar dan blijven er nog een handjevol over.

Maar in ieder geval, bedankt voor de input van iedereen.

Acties:
  • 0 Henk 'm!

  • Orphix
  • Registratie: Februari 2000
  • Niet online
YopY schreef op donderdag 26 februari 2009 @ 09:12:
Hoe bedoel je dit precies? Je forceert daar subclasses wel mee om die te implementeren, maar niet om te gebruiken, :/.
Ipv fields gebruik je enkel get..() en set.. () methods. Vanuit je base-class heb je dus ook geen fields waar je naar verwijst, maar gebruik je overal de getters/setters in je code (zie ookTemplate Method Pattern).

Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
Hrm, juistem. Ik heb het probleem ondertussen (grotendeels) opgelost door mijn eerste aanpak van (een soort van) 'builder' class te vervangen met een 'config' class oid. Ik heb een interface (aantal interfaces) gemaakt met een aantal get-methodes die elk een bepaald onderdeel van de configuratie teruggeeft aan de Builder, die de uiteindelijke eind-gebruiker (verplicht) in moet vullen. D'r is ook een (abstracte) implementatie die standaardwaarden invult voor niet-verplichte velden, zodat de gebruiker alleen de noodzakelijke configuratie in hoeft te vullen.

Dit houdt de eindgebruiker natuurlijk niet tegen om gewoon lege functies aan te maken (die null oid teruggeven), maar zorgt er wel voor dat ze dat alleen bewust kunnen doen. Daarnaast, doordat ze een functie met een specifieke naam en return-type in moeten vullen, is de code ook meer zelf-beschrijvend, waardoor de eindgebruiker ongeveer kan raden wat hij op dat moment aan het configureren is.

Ik vindt het zelf wel een leuke oplossing, er is ook veel minder 'verdedigend programmeren' voor nodig, de code van mijn 'builders' is met 2/3e verkleind, de overvloed aan constructors daarin (overloaded, met standaardwaarden hier en daar) zijn nu helemaal verwijderd, etcetera.

Ik zou nog een 'validate' functie toe kunnen voegen aan de Config class(es) die controleert of het wel juist geïmplementeerd is, maar ik denk zelf dat het nu zelf-beschrijvend genoeg is om dat achterwege te laten.
Pagina: 1