[Java] Super / Sub klasse onderscheid bepalen

Pagina: 1
Acties:
  • 217 views sinds 30-01-2008
  • Reageer

  • chrisO
  • Registratie: Mei 2003
  • Laatst online: 22-05 09:18
Ik heb 2 klassen klant (de superklasse) en vasteklant (de subklasse) .
De vaste klant heeft een aantal extra variabelen die de superklasse (klant) niet heeft.
Nu heeft de functie van een andere als invoer parameter een object van de klasse klant nodig, dit is of een vasteklant of klant. dit doe ik als volgt:

functie(Object klant) // klant is hier ofwel een vasteklant of een klant

mijn vraag is nu: kan ik op een manier bepalen binnen deze functie of het Object klant een object van de klasse klant of van de klasse vasteklant is? of is de enige oplossing hiervoor Polymorfie?

Verwijderd

Met de instanceof operator

as in:
code:
1
2
3
4
if( o instanceof VasteKlant )
  //doe iets
else
  //doe iets anders

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Polymorfie is wellicht wel de mooiste oplossing?

Maar reflection gebruiken is ook niet onhandig. Bijvoorbeeld klant.class.getSuperclass() enzo beoordelen een andere variant is bijvoorbeeld de output van getMethods bekijken op de class. En natuurlijk de instanceof variant, maar die is het minst flexibel (hardcoden van klassenamen is imho niet zo mooi).

  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
Oplossing 3 (en mijn persoonlijke favoriet als haskell-programmeur) is het Visitor Pattern

  • Robtimus
  • Registratie: November 2002
  • Laatst online: 09:46

Robtimus

me Robtimus no like you

ACM schreef op 24 maart 2004 @ 19:53:
Polymorfie is wellicht wel de mooiste oplossing?

Maar reflection gebruiken is ook niet onhandig. Bijvoorbeeld klant.class.getSuperclass() enzo beoordelen een andere variant is bijvoorbeeld de output van getMethods bekijken op de class. En natuurlijk de instanceof variant, maar die is het minst flexibel (hardcoden van klassenamen is imho niet zo mooi).
Reflection is heel mooi, maar in dit geval wat te zwaar, je weet nml al welke typen hij kan hebben: Klant of VasteKlant.
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
void func(Klant klant)
{
    if (klant instanceof VasteKlant)
    {
        // reference om steeds opnieuw te casten te vermijden
        VasteKlant vklant = (VasteKlant)klant;
        // werk met vklant
    }
    else
    {
        // werk gewoon met klant
    }
}
uitgebreide versie van nochoice

[ Voor 5% gewijzigd door Robtimus op 24-03-2004 20:15 ]

More than meets the eye
There is no I in TEAM... but there is ME
system specs


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Glimi schreef op 24 maart 2004 @ 20:06:
Oplossing 3 (en mijn persoonlijke favoriet als haskell-programmeur) is het Visitor Pattern
Visitor suckt eigelijk best wel hard omdat je hele signature zwaar naar de kloten gaat. Je kan het als volgt oplossen:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class FooCalc{

     public static int calc(Foo foo){
          FooVisitorImpl v = new FooVisitorImpl();
          foo.accepts(v);
          return v.waarde'
     }

     private static class FooVisitorImpl implements FooVisitor{
           private int waarde;

            public void visit(Foo1 foo){
                   _waarde = mooie berekening.
            }

            public void visit(Foo2 foo){
                 _waarde = andere mooie berekening.
            }
     }

}


Maar dit geeft een redelijke overhead (voor iedere call moet altijd 1 object aangemaakt worden).

En verder zijn visitors dus weer waardeloos uitbreidbaar. Stel dat in een systeem waar jij de source niet van hebt een visitor wordt gebruikt, en je gaat een nieuwe subclass introduceren, dan heb je een probleem. Maarja.. een soortgelijk probleem heb je ook als je een nieuwe functie wilt toevoegen (wat met een visitor weer wel gemakkelijk lukt).

Ik heb zelf in ieder geval nog geen gulden middenweg gevonden.

En haskell heeft trouwens geen visitors nodig, daar heb je gewoon multidispatch, dus hoef je je niet meer bezig te houden met een slap aftreksel ervan.

[ontopic]
Ik zou persoonlijk een nieuwe class introduceren: NietVasteKlant.

Dan ben je van het hele ge-emmer af. Conceptueel gezien is NietVasteKlant net zo belangrijk als VasteKlant dus dat zou ik ook willen terug zien in dit domeinmodel.

Desnoods kun je nu ook een functie introduceren bij klant: isVast en daar geef je bij VasteKlant true op terug, en bij NietVasteKlant uiteraard een false.

[ Voor 19% gewijzigd door Alarmnummer op 25-03-2004 09:49 ]


  • Robtimus
  • Registratie: November 2002
  • Laatst online: 09:46

Robtimus

me Robtimus no like you

Alarmnummer schreef op 25 maart 2004 @ 09:37:
[ontopic]
Ik zou persoonlijk een nieuwe class introduceren: NietVasteKlant.

Dan ben je van het hele ge-emmer af. Conceptueel gezien is NietVasteKlant net zo belangrijk als VasteKlant dus dat zou ik ook willen terug zien in dit domeinmodel.

Desnoods kun je nu ook een functie introduceren bij klant: isVast en daar geef je bij VasteKlant true op terug, en bij NietVasteKlant uiteraard een false.
Uiteraard wordt Klant dan een abstracte klasse?

More than meets the eye
There is no I in TEAM... but there is ME
system specs


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

IceManX schreef op 25 maart 2004 @ 11:13:
[...]
Uiteraard wordt Klant dan een abstracte klasse?
Ik zou persoonlijk dit doen:

code:
1
2
3
4
5
6
7
interface Klant

abstract class AbstractKlant implements Klant

class VasteKlant extends AbstractKlant

class NietVasteKlant extends AbstractKlant.


De vrijheid van een interface, en het gemak van een abstract class.

[edit]

Bij grotere class-hierarchieen die in de toekomst misschien nog uitgebreid gaan worden (voor util libraries), daar zet ik alles op mbv interfaces (dus ook VasteKlant en NietVasteKlant). Daarmee kan je specificatie volledig van implementatie scheiden en maakt je erg flexibel (en dat wil je vaak bij util libraries). Maar bij dit soort kleine dingen heb ik geen zin in al die overhead, dus meteen maar een class VasteKlant en NietVasteKlant.

[ Voor 35% gewijzigd door Alarmnummer op 25-03-2004 11:30 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

*kick*

niemand meer?

  • Donderwolk
  • Registratie: Januari 2002
  • Laatst online: 15-05 15:27
Er zijn gewoon meerdere wegen die naar Rome leiden, maar ook meerdere factoren die de keuze bepalen.
Denk hierbij oa aan de grootte van je project, de mate waarin je project verandert, aantal subklassen, enz.

Omdat je hier maar 1 subklasse hebt lijkt het mij het handigst om toch gewoon gebruik te maken van de instanceof operator.

Wanneer je meerdere subklassen hebt zou je eens kunnen nadenken over Visitor patterns, Polymorfie en Interfaces. Ik denk echter dat dit oplossingen zijn die voor het Klant/VasteKlant probleem wat te ver gaan.

Maar goed dat is een persoonlijke keuze, wat je zelf doet moet jij weten. :Y)

Pwnd


  • Bobco
  • Registratie: Januari 2001
  • Laatst online: 30-10-2023

Bobco

I used to dream about Verona.

Het is mij niet helemaal duidelijk waarom de Vasteklant anders moet worden behandeld dan een Klant, maar ik zou geneigd zijn om dit gewoon te implementeren in de VasteKlant en Klant classes.

Waarom zou je de buitenwereld belasten met verschillen in implementatie tussen deze 2? Door in andere classes onderscheid te maken in Klant en VasteKlant komt een gedeelte van de kennis over de interne structuur van de VasteKlant buiten de class zelf te liggen, niet zo fijn voor je encapsulatie...

With the light in our eyes, it's hard to see.


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Bobco schreef op 26 maart 2004 @ 14:10:
Het is mij niet helemaal duidelijk waarom de Vasteklant anders moet worden behandeld dan een Klant, maar ik zou geneigd zijn om dit gewoon te implementeren in de VasteKlant en Klant classes.
De vaste klant heeft een aantal extra variabelen die de superklasse (klant) niet heeft.
Waarom zou je de buitenwereld belasten met verschillen in implementatie tussen deze 2? Door in andere classes onderscheid te maken in Klant en VasteKlant komt een gedeelte van de kennis over de interne structuur van de VasteKlant buiten de class zelf te liggen, niet zo fijn voor je encapsulatie...
Daarom kun je die vast/niet vast functionaliteit ook beste bij de klant class mbv polymorfisme realiseren. Op dit manier wordt je systeem niet besmet met dit soort details. Maar je doet er wel verstandig aan om aparte classes aan te maken, en dit zou je eventueel volledig kunnen verbergen via een factory waarmee je geen weet hebt van vast/niet vast-class. Maar of dit nu zo praktisch is voor zo`n klein probleem is een 2e, overontwerpen is namelijk ook geen goeie zaak.

Er is wel een probleem aan deze polymorfe aanpak. Als er bv gui functionaliteit moet komen, zoals : getBegroetingsMessage dan zou je bij de vaste klant misschien willen zien: Beste vaste Klant.... en bij de niet vaste Klant: Beste Klant, weet u dat u korting krijgt als u vaste klant wordt? Als je deze functionaliteit mbv polymorfisme aan je domein objecten wilt toevoegen, dan worden je domein objecten dus besmet met allerlei niet-domein functionaliteit. En dat vind ik persoonlijk een slechte zaak.

Een tegenhandger van MVC is PAC en daar heb je deze problematiek in ieder geval niet. Hierbij ga je in je domein objecten ook meteen de visualisatie plaatsen. Je zou dus kunnen zeggen:

Persoon jan = ...;
Component c = jan.getFieldEditor();

De persoon class is volledig verantwoordelijk voor de gui opbouw en eigelijk hoef je ook niet meer te weten hoe Persoon nog in elkaar zit. En dit kenmerk: encapsulation is een van de hoekstenen van oo. Je zou dus kunnen zeggen dat PAC meer OO is dan MVC.

Het probleem is echt weer dat je allerlei aspecten van je systeem door elkaar gaat mixen (domein objecten, gui ) en dat is imho geen goeie zaak.

[ Voor 46% gewijzigd door Alarmnummer op 26-03-2004 15:16 ]


  • jAnO!
  • Registratie: Januari 2002
  • Laatst online: 01-05 18:22

jAnO!

lalalavanillevla

chrisO schreef op 24 maart 2004 @ 19:04:
Ik heb 2 klassen klant (de superklasse) en vasteklant (de subklasse) .
De vaste klant heeft een aantal extra variabelen die de superklasse (klant) niet heeft.
Nu heeft de functie van een andere als invoer parameter een object van de klasse klant nodig, dit is of een vasteklant of klant. dit doe ik als volgt:

functie(Object klant) // klant is hier ofwel een vasteklant of een klant

mijn vraag is nu: kan ik op een manier bepalen binnen deze functie of het Object klant een object van de klasse klant of van de klasse vasteklant is? of is de enige oplossing hiervoor Polymorfie?
waarom overload je niet gewoon?

Java:
1
2
void doeIetsMetKlant(Klant klant){...}
void doeIetsMetKlant(VasteKlant vasteKlant){...}

When some people work at a place for ten years they get ten years of experience, other people work at a place for ten years and get one year of experience ten times.


  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
jAnO! schreef op 26 maart 2004 @ 16:22:
waarom overload je niet gewoon?

Java:
1
2
void doeIetsMetKlant(Klant klant){...}
void doeIetsMetKlant(VasteKlant vasteKlant){...}
Als je runtime met de Klant werkt, terwijl het eigenlijk een VasteKlant is, dan pakt de runtime altijd het ruimte type om de call op te matchen.

[edit]
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.util.Random;

public class Application {

    public static void main( final String[] args ) {

        final Klant k = Application.getKlant( );
        new KlantHandler().doIets( k );
        System.out.println( k.toString() ); 
    }

    public static Klant getKlant( ) {

        final Random l_random = new Random( );
        
        if( l_random.nextBoolean( ) )
            return new Klant( );

        else
            return new VasteKlant();
    }

}

class Klant {

    public String toString( ) {
        
        return "Klant";
    }
}

class VasteKlant extends Klant {

        public String toString( ) {
        
        return "VasteKlant";
    }
}

class KlantHandler {

   public void doIets( final Klant p_klant ) {

    System.out.println( "Klant!" );
   }

   public void doIets( final VasteKlant p_klant ) {

    System.out.println( "VasteKlant!" );
   }

}

[ Voor 53% gewijzigd door Glimi op 26-03-2004 16:42 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:50

.oisyn

Moderator Devschuur®

Demotivational Speaker

jAnO!: omdat dat niet werkt:
Java:
1
2
3
4
5
void func ()
{
    Klant k = new VasteKlant ();
    doeIetsMetKlant (k);  // rara welke methode wordt nu aangeroepen?
}

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Glimi schreef op 26 maart 2004 @ 16:27:
[...]

Als je runtime met de Klant werkt, terwijl het eigenlijk een VasteKlant is, dan pakt de runtime altijd het ruimte type om de call op te matchen.
Dit gebeurt volgens mij al compiletime hoor. Compile time wordt bepaald welkefunctie hierbij hoort. Was het maar runtime, dan had je tenminste een pure single dispatch.

  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
Alarmnummer schreef op 26 maart 2004 @ 16:40:
Dit gebeurt volgens mij al compiletime hoor. Compile time wordt bepaald welkefunctie hierbij hoort. Was het maar runtime, dan had je tenminste een pure single dispatch.
Idd, heb het gechecked, maar als je het als Klant declareert, dan zal de compiler ook de klant aanroep nemen. Declaratie met een VasteKlant geeft natuurlijk de VasteKlant aanroep

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Glimi schreef op 26 maart 2004 @ 16:45:
[...]

Idd, heb het gechecked, maar als je het als Klant declareert, dan zal de compiler ook de klant aanroep nemen. Declaratie met een VasteKlant geeft natuurlijk de VasteKlant aanroep
Yep :) Polymorfisme is het enigste mechanisme in de meeste traditionele oo talen om runtime uit te laten zoeken welke methode implementatie je nou daadwerkelijk bedoelt (dispatch)

  • jAnO!
  • Registratie: Januari 2002
  • Laatst online: 01-05 18:22

jAnO!

lalalavanillevla

Ja dat snap ik ook wel, het ging mij er meer om dat de TS nu in allemaal oplossingsrichtingen wordt gestuurd die geent zijn op de aanname dat hij niet de mogelijkheid heeft zijn oplossing aan te passen.
(lekker lopende zin Jan... :?)

Ik bedoel dus dat hij helemaal niet pas in de methode hoeft uit te vogelen wat het voor object het is?? of praat ik nu poep?

Ik heb nl. uit zijn post niet kunnen halen of hij die klanten uit een Collection Klanten oid. tovert. Misschien maakt hij zijn klanten wel aan als:

Klant jan = new Klant();
VasteKlant piet = new VasteKlant();

(kans is wel kein ;) )

When some people work at a place for ten years they get ten years of experience, other people work at a place for ten years and get one year of experience ten times.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:50

.oisyn

Moderator Devschuur®

Demotivational Speaker

]Ik bedoel dus dat hij helemaal niet pas in de methode hoeft uit te vogelen wat het voor object het is?? of praat ik nu poep?
ja, je praat poep, omdat je gewoon ontzettend foute code schrijft op die manier. Als jij een aparte handler hebt voor VasteKlant, dan moet je in een functie die zowel een Klant als een VasteKlant accepteert gewoon op een of andere manier controleren of het wel een VasteKlant is. Met een overload heb je niet de zekerheid dat als de Klant versie wordt aangeroepen dat dat dan ook definitief een Klant is, en geen VasteKlant

Wat nu als er allemaal verschillende soorten klanten in een Vector staan, en je haalt die er allemaal uit en geef je aan je functie? Je weet dat het iig een Klant is, dus je cast ook van Object naar Klant (of je gebruikt generics die dit voor je doet). Zo'n Klant kan best een VasteKlant zijn, maar dat weet je dus niet. Je stuurt dus altijd een object die je behandelt als Klant naar de functie, terwijl in sommige gevallen het juist een VasteKlant moest zijn

[ Voor 31% gewijzigd door .oisyn op 26-03-2004 17:14 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • jAnO!
  • Registratie: Januari 2002
  • Laatst online: 01-05 18:22

jAnO!

lalalavanillevla

buiten het feit dat ik het verder eens met je ben over lelijkheid e.d.. (ik ben trouwens maar een beginner hoor.. dus eigenlijk heeft dit topic een ontzettend educatieve bijwerking voor mij, maar natuurlijk ben ik wel eigenwijs...)
.oisyn schreef op 26 maart 2004 @ 17:11:
[...]
Wat nu als er allemaal verschillende soorten klanten in een Vector staan, en je haalt die er allemaal uit en geef je aan je functie? Je weet dat het iig een Klant is, dus je cast ook van Object naar Klant (of je gebruikt generics die dit voor je doet). Zo'n Klant kan best een VasteKlant zijn, maar dat weet je dus niet. Je stuurt dus altijd een object die je behandelt als Klant naar de functie, terwijl in sommige gevallen het juist een VasteKlant moest zijn
ik zei nl wel ook nog :
Ik heb nl. uit zijn post niet kunnen halen of hij die klanten uit een Collection Klanten oid. tovert. Misschien maakt hij zijn klanten wel aan als:

Klant jan = new Klant();
VasteKlant piet = new VasteKlant();

(kans is wel kein ;) )
misschien stopt hij ze helemaal nergens in, of pas in de functie en is de funtie ervoor om ze voorin de collectie te stoppen ofsow.. zodat ze er weer als eerste eruit kunnen worden gehaald... Je weet het niet? *
Misschien wil de TS zijn licht nog even laten schijnen?

edit:
* poging banaan recht te lullen

When some people work at a place for ten years they get ten years of experience, other people work at a place for ten years and get one year of experience ten times.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:50

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ten eerste: bananen zijn krom :P ;)

Ik snap wat je bedoelt, maar het is gewoon bad practice om het zo te doen :) Als je het op die manier aanpakt heb je dus wel code die vrij snel kan breken als je het even op een andere manier doet (die intuitief ook zou horen te werken). Daarom het advies: niet doen, slechte code style ;)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1