/ Forside / Teknologi / Udvikling / Java / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
Java
#NavnPoint
molokyle 3688
Klaudi 855
strarup 740
Forvirret 660
gøgeungen 500
Teil 373
Stouenberg 360
vnc 360
pmbruun 341
10  mccracken 320
Hvordan undgår jeg instanceof?
Fra : Rune Zedeler


Dato : 11-10-07 01:09

Det siges at instanceof er en slem ting og kun bør bruges i sammenligninger.

Hvordan undgår jeg instanceof i nedenstående?

abstract class Number {
Number times(Number other);
double asDouble();
...
}

class FloatNumber extends Number {
double value;
FloatNumber times(Number other) {
return new FloatNumber(value*other.asDouble());
}
...
}

class RationalNumber extends Number {
int num;
int den;
RationalNumber times(RationalNumber other) {
return new RationalNumber(num*other->num, den*other->den);
}
Number times(Number other) {
// hvordan undgår jeg instanceof her?
if (other instanceof RationalNumber)
return times((RationalNumber)other);
else
return other.times(this);
}
...
}

-Rune

 
 
Arne Vajhøj (14-10-2007)
Kommentar
Fra : Arne Vajhøj


Dato : 14-10-07 02:48

Rune Zedeler wrote:
> Det siges at instanceof er en slem ting og kun bør bruges i
> sammenligninger.
>
> Hvordan undgår jeg instanceof i nedenstående?
>
> abstract class Number {
> Number times(Number other);
> double asDouble();
> ...
> }
>
> class FloatNumber extends Number {
> double value;
> FloatNumber times(Number other) {
> return new FloatNumber(value*other.asDouble());
> }
> ...
> }
>
> class RationalNumber extends Number {
> int num;
> int den;
> RationalNumber times(RationalNumber other) {
> return new RationalNumber(num*other->num, den*other->den);
> }
> Number times(Number other) {
> // hvordan undgår jeg instanceof her?
> if (other instanceof RationalNumber)
> return times((RationalNumber)other);
> else
> return other.times(this);
> }
> ...
> }

Jeg ville finde det OK at bruge instanceod i denne her kontekst.

Det eneste alterantiv jeg kan se er en abstrakt metode
hasSpecialRational i Number som returnerer false og så override
den i RationalNumber med en som returnerer true og teste på
den i stedet for.

Arne

Michael Zedeler (14-10-2007)
Kommentar
Fra : Michael Zedeler


Dato : 14-10-07 15:07

Arne Vajhøj wrote:
> Rune Zedeler wrote:
>> Det siges at instanceof er en slem ting og kun bør bruges i
>> sammenligninger.
>>
>> Hvordan undgår jeg instanceof i nedenstående?
>>
>> abstract class Number {
>> Number times(Number other);
>> double asDouble();
>> ...
>> }
>>
>> class FloatNumber extends Number {
>> double value;
>> FloatNumber times(Number other) {
>> return new FloatNumber(value*other.asDouble());
>> }
>> ...
>> }
>>
>> class RationalNumber extends Number {
>> int num;
>> int den;
>> RationalNumber times(RationalNumber other) {
>> return new RationalNumber(num*other->num, den*other->den);
>> }
>> Number times(Number other) {
>> // hvordan undgår jeg instanceof her?
>> if (other instanceof RationalNumber)
>> return times((RationalNumber)other);
>> else
>> return other.times(this);
>> }
>> ...
>> }
>
> Jeg ville finde det OK at bruge instanceod i denne her kontekst.

Jeg synes også at det ser fornuftigt ud fra et æstetisk synspunkt, da
klassen kun interesserer sig for om der er tale om en instans af klassen
selv, eller noget andet, men det kan da godt ende med at performe ret
dårligt?

Er det ikke netop denne type situationer, hvor man kan bruge generics
til at optimere hastigheden?

Mvh. Michael.

Rune Zedeler (14-10-2007)
Kommentar
Fra : Rune Zedeler


Dato : 14-10-07 23:57

Michael Zedeler skrev:
> Jeg synes også at det ser fornuftigt ud fra et æstetisk synspunkt, da
> klassen kun interesserer sig for om der er tale om en instans af klassen
> selv, eller noget andet, men det kan da godt ende med at performe ret
> dårligt?

Ja, jeg tror ikke man kommer ud over et stort performancetab når der
skal kunne foretages runtime-konverteringer mellem forskellige typer af tal.
Hvis performance er vigtig i en beregning med RationalNumbers vil man
vel typisk angive variablene til at være af typen RationalNumber i
stedet for Number. Så vil det være RationalNumber.times(RationalNumber)
der bliver kaldt direkte - og der vil ikke være noget performancetab.

> Er det ikke netop denne type situationer, hvor man kan bruge generics
> til at optimere hastigheden?

Det tror jeg ikke - da generics kræver at typen er kendt på compiletime.
Og hvis typen /er/ kendt på compiletime vil problemet alligevel ikke
eksistere som beskrevet ovenfor.

-Rune

Arne Vajhøj (17-10-2007)
Kommentar
Fra : Arne Vajhøj


Dato : 17-10-07 00:41

Michael Zedeler wrote:
> Arne Vajhøj wrote:
> Er det ikke netop denne type situationer, hvor man kan bruge generics
> til at optimere hastigheden?

Løser generics ikke det omvendte problem ?

Med generics gør du det samme for nogle forskellige typer.

Her er problemet at gøre noget forskelligt for nogle
forskellige typer.

Arne


Michael Zedeler (17-10-2007)
Kommentar
Fra : Michael Zedeler


Dato : 17-10-07 21:02

Arne Vajhøj wrote:
> Michael Zedeler wrote:
>> Arne Vajhøj wrote:
>> Er det ikke netop denne type situationer, hvor man kan bruge generics
>> til at optimere hastigheden?
>
> Løser generics ikke det omvendte problem ?
>
> Med generics gør du det samme for nogle forskellige typer.
>
> Her er problemet at gøre noget forskelligt for nogle
> forskellige typer.

Jo. Jeg har lige læst op på generics igen (indtil videre har jeg aldrig
brugt det) og det ser ikke ud til at kunne bruges.

Mvh. Michael.

Lasse Reichstein Nie~ (14-10-2007)
Kommentar
Fra : Lasse Reichstein Nie~


Dato : 14-10-07 16:12

Rune Zedeler <rz@daimi.au.dk> writes:

> Det siges at instanceof er en slem ting og kun bør bruges i sammenligninger.
>
> Hvordan undgår jeg instanceof i nedenstående?
....
> Number times(Number other) {
> // hvordan undgår jeg instanceof her?
> if (other instanceof RationalNumber)
> return times((RationalNumber)other);
> else
> return other.times(this);

Først og fremmest tager du en beslutning:
Skal et RationalNumber kunne ganges med ethvert andet Number eller ej?

Hvad nu hvis "other" i det ovenstående var en anden Number-implementation
der havde en lignende "times"-metode. Så ville de to stå og kalde hinanden
frem og tilbage, indtil stakken løber over.
Det er farligt at antage at "hvis jeg ikke ved hvordan vi skal gange,
så gør den anden nok", med mindre du har fuldstændig styr på hvilke
klasser der findes, og RationalNumber er den eneste med den tilgangsvinkel.

Skal "times"-metoden være kommutativ? Altså giver
n1.times(n2)
altid det samme som
n2.times(n1)
uafhængigt af hvilke Number-klasser der bruges?
Hvad skal værdien være?

Grunden til at man siger at instanceof er slem er at det nemt bryder
med Lisskovs substitutionsprincip: Enhver instans af en subklasse kan
bruges hvor et superklasse-objekt forventes.
Her forventes et Number-objekt, men metoden opfører sig forskelligt
alt efter hvilken subklasse der kommer ind. Det kan være godt nok,
men man skal holde tungen lige i munden. Hvis man ikke kender alle
subklasser, så skal man have en default-opførsel alligevel, og
så bør man overveje om det ikke er den rigtige opførsel i alle
tilfælde.


/L
--
Lasse Reichstein Nielsen - lrn@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'

Rune Zedeler (15-10-2007)
Kommentar
Fra : Rune Zedeler


Dato : 15-10-07 00:25

Lasse Reichstein Nielsen skrev:

> Først og fremmest tager du en beslutning:
> Skal et RationalNumber kunne ganges med ethvert andet Number eller ej?

Ja, og hvis det er kendt på compiletime at det andet tal også er et
RationalNumber skal multiplikationen foretages uden overhead.

> Hvad nu hvis "other" i det ovenstående var en anden Number-implementation
> der havde en lignende "times"-metode. Så ville de to stå og kalde hinanden
> frem og tilbage, indtil stakken løber over.

Det er fuldstændig rigtigt. Mit fallback var lidt for hacket.
Det skal siges at min aktuelle problemstilling er en helt anden - men at
jeg valgte at oversætte til tal da det var nemmere at forklare - og vise
et simpelt eksempel der illustrerer problemstillingen. Jeg var så lidt
for ivrig efter at forfatte et kortfattet eksempel.
Hvis jeg skulle lave disse klasser "for real" ville jeg nok have gjort
noget i stil med:

abstract class Number {
Number times(Number other) {
return new FloatNumber(asDouble()*other.asDouble());
}
abstract double asDouble();
}

class FloatNumber extends Number {
double value;
...
}

class RationalNumber extends Number {
int num;
int den;
RationalNumber times(RationalNumber other) {
return new RationalNumber(num*other.num, den*other.den);
}
Number times(Number other) {
// hvordan undgår jeg instanceof her?
if (other instanceof RationalNumber)
return times((RationalNumber)other);
else
return super.times(other);
}
...
}

-Rune

Lasse Reichstein Nie~ (15-10-2007)
Kommentar
Fra : Lasse Reichstein Nie~


Dato : 15-10-07 06:05

Rune Zedeler <rz@daimi.au.dk> writes:

> Number times(Number other) {
> // hvordan undgår jeg instanceof her?
> if (other instanceof RationalNumber)
> return times((RationalNumber)other);
> else
> return super.times(other);
> }

Ok, her undgår du ikke instanceof.
Du bruger kun instanceof med din egen klasse, og alt andet har en
acceptabel fallback, så det er så godt som det kan blive.

Andre steder hvor man ofte bruger instanceof er implementationer
af Object.equals(Object) og Comparable.compareTo(Object).
Den sidste kan dog undgås med generics nu.
Equals-metoden skal acceptere alle typer, men oftest vil man kun være
lig med noget af præcis sin egen type. Derfor vil man ofte skrive noget
i stil med:

public boolean equals(Object other) {
if (this == other) { return true; }
if (!(other instanceof MyClass)) { return false; }
MyClass otherMyClass = (MyClass) other;
return ....; // rigtig sammenligning
}


--
Lasse Reichstein Nielsen - lrn@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'

Lasse Reichstein Nie~ (15-10-2007)
Kommentar
Fra : Lasse Reichstein Nie~


Dato : 15-10-07 06:14

Lasse Reichstein Nielsen <lrn@hotpop.com> writes:

> Derfor vil man ofte skrive noget
> i stil med:
>
> public boolean equals(Object other) {
> if (this == other) { return true; }
> if (!(other instanceof MyClass)) { return false; }

Her kan man dog ofte have brug for at skrive:
if (!(other.getClass().equals(MyClass.class))) { return false;}
for at være helt sikker på at equals bliver symmetrisk hvis en
sub-klasse også overskriver den.

> MyClass otherMyClass = (MyClass) other;
> return ....; // rigtig sammenligning
> }

--
Lasse Reichstein Nielsen - lrn@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'

Søg
Reklame
Statistik
Spørgsmål : 177577
Tips : 31968
Nyheder : 719565
Indlæg : 6409071
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste