Programmering

Indre klasser

Spørgsmål: Så hvad er indre klasser godt for alligevel?

EN: Indre klasser reden i andre klasser. En normal klasse er et direkte medlem af en pakke, en topklasse. Indre klasser, som blev tilgængelige med Java 1.1, findes i fire varianter:

  • Statiske medlemsklasser
  • Medlemsklasser
  • Lokale klasser
  • Anonyme klasser

Lad os se hurtigt på hver efter hinanden.

Kort fortalt a statisk medlemsklasse er et statisk medlem af en klasse. Som enhver anden statisk metode har en statisk medlemsklasse adgang til alle statiske metoder for den overordnede eller øverste klasse.

Som en statisk medlemsklasse, a medlemsklasse defineres også som medlem af en klasse. I modsætning til den statiske sort er medlemsklassen instansspecifik og har adgang til alle metoder og medlemmer, selv forældrenes det her reference.

Lokal klasser er deklareret inden for en blok af kode og er kun synlige inden for den blok, ligesom enhver anden metodevariabel.

Endelig an anonym klasse er en lokal klasse, der ikke har noget navn.

For at besvare dit specifikke spørgsmål vil jeg fokusere på medlemmets og anonyme indre klasser, da det er dem, du sandsynligvis vil støde på og bruge. For mig kan fordelene ved indre klasser opdeles i tre kategorier: en objektorienteret fordel, en organisatorisk fordel og en tilbagekaldsfordel.

Den objektorienterede fordel

Efter min ydmyge mening er det vigtigste træk ved den indre klasse, at det giver dig mulighed for at gøre ting til objekter, som du normalt ikke ville blive til objekter. Det gør det muligt for din kode at være endnu mere objektorienteret, end den ville være uden indre klasser.

Lad os se på medlemsklassen. Da dets instans er medlem af sin overordnede forekomst, har den adgang til hvert medlem og metode i forældren. Ved første øjekast ser det måske ikke ud til meget; vi har allerede den slags adgang inden for en metode i overordnet klasse. Imidlertid tillader medlemsklassen os at tage logikken ud af forælderen og objektivere den. For eksempel kan en træklasse have en metode og mange hjælpermetoder, der udfører en søgning eller gå af træet. Fra et objektorienteret synspunkt er træet et træ, ikke en søgealgoritme. Du har dog brug for intim viden om træets datastrukturer for at udføre en søgning.

En indre klasse giver os mulighed for at fjerne logikken og placere den i sin egen klasse. Så fra et objektorienteret synspunkt har vi taget funktionalitet ud af, hvor den ikke hører hjemme, og har sat den i sin egen klasse. Gennem brugen af ​​en indre klasse har vi med succes afkoblet søgealgoritmen fra træet. For at ændre søgealgoritmen kan vi blot bytte i en ny klasse. Jeg kunne fortsætte, men det åbner vores kode for mange af fordelene ved objektorienterede teknikker.

Den organisatoriske fordel

Objektorienteret design er ikke alles ting, men heldigvis giver indre klasser mere. Fra et organisatorisk synspunkt giver indre klasser os mulighed for yderligere at organisere vores pakkestruktur ved hjælp af navneområder. I stedet for at dumpe alt i en flad pakke kan klasser yderligere indlejres i klasser. Eksplicit, uden indre klasser, var vi begrænset til følgende hierarkistruktur:

pakke1 klasse 1 klasse 2 ... klasse n ... pakke n 

Med indre klasser kan vi gøre følgende:

pakke 1 klasse 1 klasse 2 klasse 1 klasse 2 ... klasse n 

Brugt omhyggeligt kan indre klasser give et strukturelt hierarki, der mere naturligt passer til dine klasser.

Tilbagekaldelsesfordelen

Indre medlemsklasser og anonyme klasser giver begge en praktisk metode til at definere tilbagekald. Det mest oplagte eksempel vedrører GUI-kode. Imidlertid kan anvendelsen af ​​tilbagekaldet omfatte mange domæner.

De fleste Java GUI'er har en slags komponent, der starter en actionPerformed () metodeopkald. Desværre har de fleste udviklere simpelthen deres hovedvinduesimplement ActionListener. Som et resultat deler alle komponenter det samme actionPerformed () metode. For at finde ud af, hvilken komponent der udførte handlingen, er der normalt en kæmpe, grim afbryder i actionPerformed () metode.

Her er et eksempel på en monolitisk implementering:

offentlig klasse SomeGUI udvider JFrame implementerer ActionListener {beskyttet JButton knap1; beskyttet JButton-knap2; ... beskyttet JButton-knapN; offentlig ugyldig handling Udført (ActionEvent e) {hvis (e.getSource () == knap1) {// gør noget} andet hvis (e.getSource () == knap2) {... du får billedet 

Når du ser kontakter eller store hvis/hvis ellers blokke, høje alarmklokker skal begynde at ringe i dit sind. Generelt er sådanne konstruktioner dårligt objektorienteret design, da en ændring i et afsnit af koden kan kræve en tilsvarende ændring i switch-sætningen. Indre medlemsklasser og anonyme klasser giver os mulighed for at komme væk fra det skiftede actionPerformed () metode.

I stedet kan vi definere en indre klasse, der implementeres ActionListener for hver komponent, som vi vil lytte til. Det kan resultere i mange indre klasser. Vi kan dog undgå store switch-erklæringer og få den ekstra bonus at indkapsle vores handlingslogik. Desuden kan denne tilgang forbedre ydeevnen. I en switch, hvor der er n sammenligninger, kan vi forvente n / 2 sammenligninger i gennemsnittet. Indre klasser giver os mulighed for at oprette en 1: 1 korrespondance mellem handlingsudøveren og handlingslytteren. I en stor GUI kan sådanne optimeringer have en væsentlig indvirkning på ydeevnen. En anonym tilgang kan se sådan ud:

offentlig klasse SomeGUI udvider JFrame {... knapmedeldeklarationer ... beskyttet ugyldig buildGUI () {button1 = ny JButton (); knap2 = ny JButton (); ... button1.addActionListener (new java.awt.event.ActionListener () {public void actionPerformed (java.awt.event.ActionEvent e) {// do something}}); .. gentag for hver knap 

Ved hjælp af indre medlemsklasser vil det samme program se sådan ud:

offentlig klasse SomeGUI udvider JFrame {... knappemedlemdeklarationer // indre klassedefinitioner klasse Button1Handler implementerer ActionListener {offentlig ugyldig handlingPerformeret (ActionEvent e) {// gør noget}} ... definer en indre medlemsklasse for hver knapbeskyttet ugyldig buildGUI () {// initialiser knapperne button1 = ny JButton (); knap2 = ny JButton (); ... // registrer en intern klassehandling-lytterinstans // for hver knap-knap1.addActionListener (ny Button1Handler ()); .. gentag for hver knap 

Da indre klasser har adgang til alt i forældrene, kan vi flytte enhver logik, der ville have vist sig i en monolitisk actionPerformed () implementering til en indre klasse.

Jeg foretrækker at bruge medlemsklasser som tilbagekald. Det er dog et spørgsmål om personlig præference. Jeg føler bare for mange anonyme klasser rodkode. Jeg føler også, at anonyme klasser kan blive uhåndterlige, hvis de er større end en eller to linjer.

Ulemper?

Som med alt andet skal du tage det gode med det dårlige. Indvendige klasser har deres ulemper. Fra et vedligeholdelsessynspunkt kan uerfarne Java-udviklere måske finde den indre klasse vanskelig at forstå. Brug af indre klasser øger også det samlede antal klasser i din kode. Desuden set fra et udviklingssynspunkt de fleste Java-værktøjer op lidt kort på deres støtte til indre klasser. For eksempel bruger jeg IBMs VisualAge til Java til min daglige kodning. Mens indre klasser kompileres i VisualAge, er der ingen browser eller skabelon til indre klasser. I stedet skal du blot skrive den indre klasse direkte i klassedefinitionen. Det gør desværre browsing i den indre klasse vanskelig. Det er også svært at skrive, da du mister mange af VisualAges hjælp til kodefærdiggørelse, når du skriver ind i klassedefinitionen eller bruger en indre klasse.

Tony Sintes er seniorkonsulent hos ObjectWave med speciale i telekommunikation. Sintes, en Sun-certificeret Java 1.1-programmør og Java 2-udvikler, har arbejdet med Java siden 1997.

Lær mere om dette emne

  • "Indre klassespecifikation" fra Sun giver et dybtgående kig på indre klasser

    //java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html

Denne historie, "Indre klasser" blev oprindeligt udgivet af JavaWorld.