Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Noen objekter har hovedsaklig som formål å huske og håndtere data, og disse kaller vi data- eller tilstandsorienterte. Et eksempel på dette er et Person-objekt som hånderer data tilsvarende det en finner på et visittkort. Et slik objekt gjør ikke så mye mer enn å lagre attributt-verdier, og tilbyr (stort sett bare) operasjoner for å lese og endre attributtene.

Enkle verdier

Anta at Person-objektet håndterer verdier for navn, fødselsdato og e-post-adresse. Hvert Person-objekt vil ha unike verdier, som leses og settes med egne operasjoner. Før en definerer disse operasjonene må en gi verdiene navn og bestemme hvilken datatype som er logisk for hvert av dem. Datatypene vil vi finne igjen i parameter- og returntypene for getter- og setter-operasjonene. F.eks. kan vi kalle bruke fullName og String for navnet til personen og det vil gi opphav til operasjonene String getFullName() og void setFullName(String). En mulig innkapsling av disse verdiene er vist under.

...

PlantUML Macro
titleImplementasjon av navn, fødselsdato og e-post
class Person {
	-String name
	-Date dateOfBirth
	-String emailUser
	-String emailDomain


	+String getFullName()
	+void setFullName(String)
	+Date getDateOfBirth()
	+void setDateOfBirth(Date)
	+String getEmail()
	+void setEmail(String)
}

Multiple verdier

Håndtering av attributter for enkeltverdier er nokså enkelt, men når ett attributt tilsvarer mange verdier, så blir det mer komplisert, kanskje mest fordi det er flere valg å ta omkring både innkapslingsmetoder og implementasjon av attributtene. Ta som eksempel håndtering av barna til en person. Siden en kan ha flere av dem, så kan en ikke innkapsle dem med Person getChild() og setChild(Person). En variant er å bruke tabeller, altså Person[] getChildren() og void setChildren(Person[]), men det vil gjøre enkle operasjoner som å legge til barn mer komplisert å kode for de som bruker Person-klassen. Derfor er det bedre å velge en innkapsling som er mer skreddersydd for bruken av dataene. Tre forslag er vist under:

PlantUML Macro
titleInnkapsling av barn variant 1
class Person {
	+boolean containsChild(Person)
	+Iterator<Person> getChildren()
	+void addChild(Person)
	+void removeChild(Person)
}	
PlantUML Macro
titleInnkapsling av barn variant 2
class Person {
	+int getChildCount()
	+int indexOfChild()
	+Person getChild(int)
	+void addChild(Person)
	+void removeChild(Person)
}
PlantUML Macro
titleInnkapsling av barn variant 3
class Person {
	+int getChildCount()
	+int getIndexOfChild()
	+Person getChild(int)
	+void addChild(int, Person)
	+void removeChild(int)
}

Variant 1 gir mulighet til å sjekke om en person har en annen person som barn, gå gjennom alle barna vha. en såkalt iterator (se Iterator) og legge til og fjerne barn. Merk at ingen metoder knytter nummer til barna, så skal en hente ut barn nr. 3, så må en be om alle og hoppe over de to første (om de finnes). Variant 2 gjør det enklere å hente ut barn basert på indeks (nummer i rekka), men ikke endre på rekkefølgen, slik variant 3 gir mulighet for. Hvilken av disse variantene en bør velge er avhengig av hva det er naturlig for andre klasser å gjøre med person-barn-koblingen. For andre typer koblinger kan det være begrensninger som gjør at noen metoder utelates eller en forventet bruk som gjør at en tilbyr et rikere utvalg, f.eks. en kombinasjon av flere varianter. Det vesentlige er 1) at en vurderer hvilke logiske operasjoner en er tjent med og 2) at en følger etablerte konvensjoner for navngiving og signaturer.

Standardoperasjoner versus logiske operasjoner

Når en skal innkapsle verdier, er det lettvint å bruke for navngiving og signaturer, slik vi har gjort over. Men en skal være forsiktig med å gjøre dette ukritisk, siden det ikke alltid stemmer med den iboende logikken til og bruken av verdien. Ta en konto som eksempel, som kan ses på som en innkapsling av et beløp eller balanse. Det er fort gjort å definere en inkapsling som vist til venstre under, men er dette riktig? Det er riktignok naturlig å kunne spørre om balansen, men en setter jo sjelden balansen direkte. I stedet setter en inn og tar ut beløp, altså legger til eller trekker fra. Noen ganger påløper det ulike gebyr for hver av disse, så det er også en grunn til å skille dem fra hverandre. Derfor er innkapslingen til høyre under bedre.

PlantUML Macro
titleInnkapsling med standardoperasjoner
class Account {
	int getBalance()
	void setBalance(int)
}
PlantUML Macro
titleInnkapsling med tilpassede operasjoner
class Account {
	int getBalance()
	void deposit(int)
	int withdraw(int)
}