Motivasjonen for innkapsling er todelt:
- Det er viktig å sikre at tilstanden til alle objektene er gyldig. Dette gjøres best ved at alle endringer av tilstanden skjer ved å kalle objektets metoder, heller enn å endre på attributtene direkte. På denne måten slipper andre objekter å kjenne til alle reglene for gyldighet og konsistens, og koden blir mer robust ved at all logikk om attributter og regler samles i én klasse.
- Det er viktig at koden for en klasse ikke er avhengig av detaljer i en annen, f.eks. eksakt hvilke attributter og datatyper som brukes for å representere data, fordi dette gjør endringer lettere å håndtere.
Ta som eksempel representasjon av fornavn og etternavn i et Person-objekt. Dette kan gjøres med ett java.lang.String-attributt, med fornavn og etternavn skilt med mellomrom, eller to separate java.lang.String-attributter, ett for fornavn og ett for etternavn. Uansett hvilken konkret representasjon som velges, så handler det logisk sett om å håndtere to (uavhengige) verdier og det er ingen grunn til at detaljer om hvordan representasjonen gjøres skal være kjent for andre klasser. Klassen definerer derfor operasjoner for både å lese og endre disse to verdiene, som lar seg implementere av begge løsningsalternativene. Hvilket alternativ man faktisk velger er en detalj som andre klasser ikke behøver bry seg om. Dette er illustrert i følgende figur:
Innkapslingen av fornavn- og etternavn-verdiene er representert ved den første klassen, mens de to andre klassene er alternative implementasjoner som støtter denne innkapslingen. Andre klasser bruker bare operasjonene og trenger ikke bry seg om eller gjøre seg avhengig av hvilket alternativ som er valgt. En kan dermed bytte mellom implementasjonsalternativ 1 og 2 uten at andre klasser blir påvirket.
Her er koden for de to alternative implementasjonene av Person, navngitt som Person1 og Person2, for å gjøre det enklere å importere dem. Person1 har to String-felt, en for fornavn og en for etternavn, mens Person2 har ett String felt for fullt navn. Begge implementerer som sagt de samme metodene og kan i praksis erstatte hverandre (bortsett fra konstruktørene).
Synlighetsmodifikatorer
Innkapsling består altså av å definere et sett operasjoner for sikker (og indirekte) tilgang til data, istedenfor å gi direkte tilgang til attributter og dermed lekke detaljer om implementasjonsteknikken til andre klasser. For å gjøre innkapslingen tydelig kan en angi i diagrammer den såkalte synligheten til navn, dvs. hvilke som skal være offentlig (kjent) og hvilke som skal være private. De offentlige skal være mulige å bruke (referere til) utenfor klassen og de private umulige. Dette illustreres med henholdsvis grønne og røde punkter eller + og - foran navnene, som vist i figuren under.
Tilsvarende tilbyr mange objektorienterte språk mekanismer såkalte synlighetsmodifikatorer for å deklarere hvilke navn som skal være offentlige og private. Alternativ 1 over vil kodes som følger:
class Person { // private fields private String givenName; private String familyName; // public methods public String getGivenName() { ... } public void setGivenName(String givenName) { ... } public String getFamilyName() { ... } public void setFamilyName(String familyName) { ... } }
Merk at offentlig og privat synlighet kan brukes for både operasjoner og attributter alt ettersom de oppfattes som en del av innkapslingen eller ikke (eller om innkapsling er viktig). Grunnregelen er at alle attributter er private, mens utvalgte operasjoner, de som er en del av innkapslingen, er offentlige. Men det er opp til programmereren å tenke gjennom hvilke som skal brukes hvor.