Programmering

Design med statiske medlemmer

Selvom Java i vid udstrækning er objektorienteret, er det ikke en ren objektorienteret sprog. En af grundene til, at Java ikke er rent objektorienteret, er at ikke alt i det er et objekt. For eksempel giver Java dig mulighed for at erklære variabler af primitive typer (int, flyde, boolskosv.), der ikke er genstande. Og Java har statiske felter og metoder, som er uafhængige og adskilte fra objekter. Denne artikel giver råd om, hvordan du bruger statiske felter og metoder i et Java-program, samtidig med at du opretholder et objektorienteret fokus i dine designs.

Levetiden for en klasse i en Java-virtuel maskine (JVM) har mange ligheder med et objekts levetid. Ligesom et objekt kan have tilstand, repræsenteret af værdierne for dets instansvariabler, kan en klasse have tilstand, repræsenteret af værdierne for dets klassevariabler. Ligesom JVM indstiller instansvariabler til standardindledende værdier inden udførelse af initialiseringskode, indstiller JVM klassevariabler til standardindledende værdier inden udførelse af initialiseringskode. Og ligesom objekter kan klasser indsamles skrald, hvis de ikke længere henvises til af den kørende applikation.

Ikke desto mindre findes der betydelige forskelle mellem klasser og objekter. Måske er den vigtigste forskel den måde, hvorpå instans og klassemetoder påberåbes: instansmetoder er (for det meste) dynamisk bundet, men klassemetoder er statisk bundet. (I tre specielle tilfælde er instansmetoder ikke dynamisk bundet: påkaldelse af private instansmetoder, påkaldelse af i det metoder (konstruktører) og påkald med super nøgleord. Se Ressourcer for mere information.)

En anden forskel mellem klasser og objekter er graden af ​​skjulning af data, der gives af de private adgangsniveauer. Hvis en instansvariabel erklæres privat, kan kun instansmetoder få adgang til den. Dette giver dig mulighed for at sikre instansdataens integritet og gøre objekter trådsikre. Resten af ​​programmet kan ikke få adgang til disse instansvariabler direkte, men skal gennemgå instansmetoderne for at manipulere instansvariablerne. I et forsøg på at få en klasse til at opføre sig som et veldesignet objekt kan du gøre klassevariabler private og definere klassemetoder, der manipulerer dem. Ikke desto mindre får du ikke så god garanti for trådsikkerhed eller endda dataintegritet på denne måde, fordi en bestemt type kode har et særligt privilegium, der giver dem direkte adgang til private klassevariabler: instansmetoder og endda initialiseringer af instans variabler, kan få adgang til disse private klassevariabler direkte.

Så de statiske felter og metoder for klasser, selvom de på mange måder ligner eksempelfelterne og metoderne for objekter, har betydelige forskelle, der skal påvirke den måde, du bruger dem på i design.

Behandler klasser som objekter

Når du designer Java-programmer, vil du sandsynligvis støde på mange situationer, hvor du føler behov for et objekt, der fungerer på nogle måder som en klasse. Du vil f.eks. Have et objekt, hvis levetid svarer til klassens levetid. Eller du vil måske have et objekt, der ligesom en klasse begrænser sig til en enkelt eksempel i et givet navn plads.

I designsituationer som disse kan det være fristende at oprette en klasse og bruge den som et objekt for at definere klassevariabler, gøre dem private og definere nogle offentlige klassemetoder, der manipulerer klassevariablerne. Som et objekt har en sådan klasse tilstand. Ligesom et veldesignet objekt er variablerne, der definerer staten private, og omverdenen kan kun påvirke denne tilstand ved at påberåbe sig klassemetoderne.

Desværre findes der nogle problemer med denne "klasse-som-objekt" tilgang. Fordi klassemetoder er statisk bundet, vil din klasse-som-objekt ikke nyde fleksibilitetsfordelene ved polymorfisme og opkastning. (For definitioner af polymorfisme og dynamisk binding, se artiklen Designteknikker, Sammensætning versus arv.) Polymorfisme er muliggjort, og opkastning er nyttig ved dynamisk binding, men klassemetoder er ikke dynamisk bundet. Hvis nogen underklasserer din klasse-som-objekt, kan de ikke tilsidesætte dine klassemetoder ved at erklære klassemetoder med samme navn de vil kun være i stand til det skjule dem. Når en af ​​disse omdefinerede klassemetoder påberåbes, vælger JVM den metodeimplementering, der skal udføres, ikke af klassen af ​​et objekt ved kørsel, men af ​​typen af ​​en variabel på kompileringstidspunktet.

Derudover er trådsikkerheden og dataintegriteten, der opnås ved din omhyggelige implementering af klassemetoderne i din klasse-som-objekt, som et hus bygget af halm. Din trådsikkerhed og dataintegritet garanteres, så længe alle bruger klassemetoderne til at manipulere den tilstand, der er gemt i klassevariablerne. Men en skødesløs eller clueless programmør kunne med tilføjelse af en instansmetode, der direkte får adgang til dine private klassevariabler, utilsigtet blæse og puste og blæse din tråds sikkerhed og dataintegritet væk.

Af denne grund er min hovedretningslinje vedrørende klassevariabler og klassemetoder:

Behandl ikke klasser som genstande.

Med andre ord må du ikke designe med statiske felter og metoder i en klasse, som om de var et objekts felter og metoder.

Hvis du vil have en tilstand og adfærd, hvis levetid svarer til en klasses, skal du undgå at bruge klassevariabler og klassemetoder til at simulere et objekt. Opret i stedet et faktisk objekt, og brug en klassevariabel til at holde en reference til det og klassemetoder for at give adgang til objektreferencen. Hvis du vil sikre, at der kun findes en forekomst af en eller anden tilstand og adfærd i et enkelt navneområde, skal du ikke prøve at designe en klasse, der simulerer et objekt. Opret i stedet en singleton - et objekt garanteret kun har én forekomst pr. navneområde.

Så hvad er klassemedlemmer gode til?

Efter min mening er den bedste tankegang at dyrke, når man designer Java-programmer, at tænke objekter, objekter, objekter. Fokuser på at designe store objekter og tænk på klasser primært som tegninger til objekter - strukturen, hvor du definerer instansvariabler og instansmetoder, der udgør dine veldesignede objekter. Derudover kan du tænke på klasser som at levere et par specielle tjenester, som objekter ikke kan levere eller ikke kan levere så elegant. Tænk på klasser som:

  • det rette sted at definere "hjælpemetoder" (metoder, der tager input og kun leverer output gennem videregående parametre og returværdien)
  • en måde at kontrollere adgangen til objekter og data på

Hjælpemetoder

Metoder, der ikke manipulerer eller bruger tilstanden for et objekt eller klasse, kalder jeg "hjælpemetoder". Hjælpemetoder returnerer blot en værdi (eller værdier), der kun beregnes ud fra data, der sendes til metoden som parametre. Du bør gøre sådanne metoder statiske og placere dem i den klasse, der er mest relateret til den service, metoden leverer.

Et eksempel på en hjælpemetode er String copyValueOf (char [] data) metode til klasse Snor. Denne metode producerer dens output, en returværdi af typen Snorudelukkende fra dets inputparameter en række af chars. Fordi copyValueOf () hverken bruger eller påvirker tilstanden for noget objekt eller klasse, det er en hjælpemetode. Og som alle hjælpemetoder skal være, copyValueOf () er en klassemetode.

Så en af ​​de vigtigste måder at bruge klassemetoder er som hjælpemetoder - metoder, der kun returnerer output beregnet ud fra inputparametre. Andre anvendelser af klassemetoder involverer klassevariabler.

Klassevariabler til skjulning af data

Et af de grundlæggende forskrifter i objektorienteret programmering er data gemmer sig - at begrænse adgangen til data for at minimere afhængigheden mellem programmets dele. Hvis et bestemt stykke data har begrænset tilgængelighed, kan disse data ændre sig uden at bryde de dele af programmet, der ikke kan få adgang til dataene.

Hvis der f.eks. Kun er brug for et objekt af forekomster af en bestemt klasse, kan en henvisning til det gemmes i en privat klassevariabel. Dette giver alle forekomster af denne klasse praktisk adgang til det objekt - forekomsterne bruger det bare direkte - men ingen anden kode andre steder i programmet kan komme til det. På en lignende måde kan du bruge pakkeadgang og beskyttede klassevariabler til at reducere synligheden af ​​objekter, der skal deles af alle medlemmer af en pakke og underklasser.

Offentlige klassevariabler er en anden historie. Hvis en offentlig klassevariabel ikke er endelig, er den en global variabel: den ubehagelige konstruktion, der er modsætningen til dataskydning. Der er aldrig nogen undskyldning for en offentlig klassevariabel, medmindre den er endelig.

Endelige offentlige klassevariabler, hvad enten det er primitiv type eller objektreference, tjener et nyttigt formål. Variabler af primitive typer eller af type Snor er simpelthen konstanter, som generelt hjælper med at gøre programmer mere fleksible (lettere at ændre). Kode, der bruger konstanter, er lettere at ændre, fordi du kan ændre den konstante værdi ét sted. Offentlige endelige klassevariabler af referencetyper giver dig mulighed for at give global adgang til objekter, der er nødvendige globalt. For eksempel, System.in, System.outog System.err er offentlige slutklassevariabler, der giver global adgang til standardindgangsoutput og fejlstrømme.

Således er den vigtigste måde at se klassevariabler på som en mekanisme til at begrænse tilgængeligheden af ​​(hvilket betyder at skjule) variabler eller objekter. Når du kombinerer klassemetoder med klassevariabler, kan du implementere endnu mere komplicerede adgangspolitikker.

Brug af klassemetoder med klassevariabler

Bortset fra at fungere som hjælpemetoder, kan klassemetoder bruges til at kontrollere adgang til objekter, der er gemt i klassevariabler - især til at kontrollere, hvordan objekterne oprettes eller styres. To eksempler på denne type klassemetode er setSecurityManager () og getSecurityManager () metoder til klasse System. Sikkerhedsadministratoren for et program er et objekt, der ligesom standardinput-, output- og fejlstrømmene er nødvendigt mange forskellige steder. I modsætning til standard I / O-streamobjekter lagres en henvisning til sikkerhedsadministratoren imidlertid ikke i en offentlig endelig klassevariabel. Security manager-objektet er gemt i en privat klassevariabel, og sæt- og get-metoderne implementerer en særlig adgangspolitik for objektet.

Java's sikkerhedsmodel lægger en særlig begrænsning på sikkerhedsadministratoren. Forud for Java 2 (tidligere kendt som JDK 1.2) begyndte en applikation sit liv uden nogen sikkerhedsadministrator (getSecurityManager () vendt tilbage nul). Det første opkald til setSecurityManager () etablerede sikkerhedschefen, som derefter ikke fik lov til at ændre. Eventuelle efterfølgende opkald til setSecurityManager () ville give en sikkerhedsundtagelse. I Java 2 starter applikationen altid med en sikkerhedsadministrator, men svarer til de tidligere versioner, den setSecurityManager () metode giver dig mulighed for at lave om sikkerhedschefen højst én gang.

Sikkerhedsadministratoren giver et godt eksempel på, hvordan klassemetoder kan bruges sammen med private klassevariabler til at implementere en særlig adgangspolitik for objekter, der henvises til af klassevariablerne. Bortset fra hjælpemetoder, tænk på klassemetoder som middel til at etablere særlige adgangspolitikker til objektreferencer og data gemt i klassevariabler.

Retningslinier

Hovedpunktet i rådgivningen i denne artikel er:

Behandl ikke klasser som genstande.

Hvis du har brug for et objekt, skal du oprette et objekt. Begræns din brug af klassevariabler og metoder til at definere hjælpemetoder og implementere særlige former for adgangspolitikker for objekter og primitive typer, der er gemt i klassevariabler. Selvom det ikke er et rent objektorienteret sprog, er Java alligevel objektorienteret i høj grad, og dit design skal afspejle det. Tænk objekter.

Næste måned

Næste måned Designteknikker artiklen vil være den sidste i denne kolonne. Jeg begynder snart at skrive en bog baseret på Design Techniques-materialet, Fleksibel Java, og vil placere dette materiale på mit websted, mens jeg går. Så følg dette projekt sammen og send mig feedback. Efter en pause på en måned eller to er jeg tilbage kl JavaWorld og SunWorld med en ny kolonne fokuseret på Jini.

En anmodning om læserdeltagelse

Jeg opfordrer dine kommentarer, kritik, forslag, flammer - alle former for feedback - om materialet præsenteret i denne kolonne. Hvis du er uenig i noget, eller har noget at tilføje, så lad mig det vide.

Du kan deltage i et diskussionsforum viet til dette materiale, indtaste en kommentar via formularen i bunden af ​​artiklen eller e-maile mig direkte ved hjælp af linket i min biografi nedenfor.

Bill Venners har skrevet professionelt software i 12 år. Baseret i Silicon Valley leverer han softwarekonsulent- og træningstjenester under navnet Artima Software Company. Gennem årene har han udviklet software til forbrugerelektronik, uddannelse, halvleder og livsforsikringsindustri. Han har programmeret på mange sprog på mange platforme: monteringssprog på forskellige mikroprocessorer, C på Unix, C ++ på Windows, Java på nettet. Han er forfatter til bogen Inside the Java Virtual Machine, udgivet af McGraw-Hill.