mandag den 30. juni 2008

Indre klasser

I, mine faste læsere, kender mig godt nok til at vide, at det ikke er samfundskritik, som overskriften lægger op til. I stedet vil jeg filosofere lidt over den syntaktiske finurlig med dette navn, som jeg har stiftet bekendskab med i programmeringssproget Java.

Det, som har inspireret mig, er et indlæg på Michael Feathers' blog: Are Nested Classes Really a Good Idea? Jeg kan godt afsløre her, at det synes han ikke, men han er fornuftig nok til at mene, at det mest er et spørgsmål om stil. Indlægget er ikke længere end, at jeg vil opfordre til, at man selv læser det.

Langt hen ad vejen er jeg enig med Michael Feathers - når de indre klasser har tyngde nok til at være "rigtige" klasser, så er det ofte sådan, at det er bedre at gøre dem til det - altså rigtige klasser for sig selv. Indre klasser er ... ja, ikke sådan direkte forkerte, bare akavede - de ødelægger ofte rytmen i programmet.

Når jeg koder, så skriver jeg ofte og gerne indre klasser. Det sker, når jeg under kodningen ser et skift i abstraktionsniveauet, eller måske identificerer jeg et afvigende ansvarsområde; det er de her små urenheder, som måske - måske ikke - er starten til udkrystalisering ... og det er her, at jeg ofte bruger indre klasser. Man kan mene, at jeg her lige så godt kunne have lavet en rigtig klasse fra starten af, men det meget hurtigere - og på sin vis også langt mere uforpligtende - lige at lave en indre klasse.

På det tidspunkt, hvor jeg kan mærke, at nu har koden fundet et naturlig leje, så er der en tendens til, at jeg løber de indre klasser igennem. De indre klasser, som har tyngde og substans, vil jeg som tommelfingerregel forfremme til "rigtige" klasser - og for de øvrige vil jeg ofte overveje, om ikke der findes alternativer, som lige så vel kan kommunikere den "lille" indre klasses struktur og hensigt. Det er sjældent, at jeg committer kode med indre klasser, som bare er klasser (i modsætning til closure-agtige indre klasser, men det kommer jeg til).

Måske er min fremgangsmåde opstået fordi, at jeg kommet til Java via Pascal - jeg husker stadig smerten ved ikke at kunne lave lokale funktioner og procedurer: Jeg følte, at jeg blev tvunget til at gøre klassen ujævn i sin natur, og jeg havde svært ved at leve med, at jeg ikke kunne begrænse scope for en metode til en sub-kontekst. I virkeligheden, så har det vist sig, at jeg kan komme langt med at dele klassen op i interface og implementation (og understrege dette med bevidst brug af synlighed) - og hvor det ikke er nok, så er det ofte fordi, at jeg prøver at gøre for meget på en gang.

Det, som normalt får mig til at tøve en kende, er, når den indre klasser er meget tæt koblet til den ydre klasse, og måske endda nært forbundet til implementationen af den. Tit er det bare dovenskab eller manglende klarhed i ansvarfordelingen - men tit er det også ubehaget ved at forurene pakkens interface med noget alt for detajleret og måske internt af natur; for den oprindelige ydre klasse var ment til at skulle bruges for andre udefra, mens den indre klasse mere var en service for den oprindelige yde klasse. Løsningen er den samme, som for metoder i klasser: man erklærer kun det, som er del af interfacet for public (en lille sidebemærkning: lige så vel som klasser har et interface, så har pakker det også - og ofte drevet af de samme overvejelser; og når Java får et eksplicit modulbegrebet, så får vi endnu et niveau, at definere interfaces på ... men det er en anden historie).

Javas "far", James Gosling, skrev for nyligt under titlen Closures bl.a. flg.:
In the early days of Java the lack of closures was pretty painful, and so inner classes were born: an uncomfortable compromise that attempted to avoid a number of hard issues.
Indre klasser er mao. noget, som ikke engang dets ophav vil kendes ved!

Closures er (eller måske rettere: har indtil for nyligt været) meget omdiskuteret i Java kredse, og det er vel netop det sted, hvor jeg selv anvender indre klasser mest eksplicit, nemlig når jeg gerne vil skille det generelle fra det specifikke. Man kan selvfølgelig prøve med template method og nedarvning, men personligt, så fortrækker jeg ofte noget, som i stedet bruger komposition (og derfor mere ligner strategy): I den generiske del erklæres et indre interface, og når det generiske skal anvendes, så bliver interface som oftest implemeteret ved en indre klasse hos anvenderen.

Closures vil da gøre dette nemmere, og den typiske indvending imod closures, nemlig at de ofte er anonyme, er, på samme måde som ved anonyme indre klasser, selvvalgt - og vel også i bund og grund et spørgsmål om stil. Men netop her er smerten ikke så stor, for indre klasser løser faktisk den del rimeligt OK - der findes værre dele af Java. Synes jeg.

Så, for lige at vende tilbage, og svare på spørgsmålet i Michael Feathers' overskrift: Nej, indre klasser er ikke ligefrem nogen genial ide - men på den anden side heller ikke nogen udpræget dårlig ide ... hvis bare man bruger den med omtanke og omhu. Og det kan man jo sige om så meget!

Ingen kommentarer: