Denna bok är bara påbörjad och saknar fortfarande mycket. Det är öppet för vem som helst att bidra till denna bok, liksom alla andra böcker. Om du märker att något saknas eller är felaktigt, tveka inte att lägga till eller redigera. Du kan träna lite i sandlådan innan du gör mer avancerade ändringar.


Varför objektorienterad programmering?

redigera

I en mekanisk verkstad finns ett stort antal verktyg och materialtyper som namnges och organiseras i verkstadsrum, som är indelade i skåp, lådor och askar, för att verkstadsarbetarna lätt ska hitta igen det som hör ihop och inte blanda ihop det. Ibland låser man in verktyg och material för att ingen av misstag ska använda fel verktyg på fel material. Lackverkstadens verktyg och material särskiljs från plåtverkstadens, motorverkstadens och elektronikverkstadens. Verktyg kan heta lika, men namnen kan ha olika betydelse utfrån det verkstadsrum de används i. Exempelvis är en lödkolv i plåtverkstaden större än en i elektronikverktaden, och får inte användas på elektronikmaterial eftersom det kan skadas. Verktygens konstruktionsritningar och materialets tillverkningsmallar arkiveras i en lämplig struktur och under lämpliga namn så att de kan kopieras, återanvändas och vidareutvecklas för att skapa nya verktyg och materialtyper. Man organiserar verkstaden i syfte att man i framtiden snabbt ska kunna utöka den så att den kan hantera ytterligare materialtyper utan att riskera att misstag görs. Man vill i så fall omorganisera så få verkstadsrum och verktygslådor som möjligt, man vill återanvända de gamla verktygskonstruktionerna så långt som möjligt på det nya materialet, och ta fram anpassade varianter genom att utgå från befintliga konstruktionsritningar och tillverkningsmallar och ändra på så få ställen som möjligt. I en liten hemmaverkstad kan detta sätt att organisera skapa merarbete, men det kan bespara mycket arbete i en storskalig verkstadsproduktion.

På liknade sätt behöver man inom storskalig programutveckling hålla reda på många olika programfunktioner som vi här kallar metoder ("verktyg" i verkstadsliknelsen) och en stor mängd data ("material"). Man vill förhindra att programutvecklaren av misstag använder fel metod på fel data för att undvika att data ändras på ett sätt som det inte var tänkt. Man vill kunna återanvända programkod och bara ändra på några få ställan i programmet om man ska lägga till ny funktionalitet, för att undvika att introducera fel.

Objektorientering används i syfte att uppnå detta, genom att namnge, gruppera, återanvända och låsa in metoder och data som hör ihop. Objektorientering är ett sätt att beskriva för en dator hur den ska se på världen, hur data ska struktureras och hur metoder ska skapas och användas. Även deras relationer till varandra beskrivs. Objektorientering ska försöka likna en människas sätt att se på saker, att man grupperar metoder och data som hör ihop i objekt (lådor, skåp, förråd och verkstadsrum i ovanstående liknelse), och skapar objekten som instanser (kopior) av en tillverkningsmall som vi kallar klass.

Skillnad mot icke objektorienterad programmering

redigera

Programspråk

redigera

Datorspråk som inte möjliggör objektorientering är t.ex. C.

Datorspråk som enbart är avsedda för objektorientering är t.ex. Smalltalk och Java.

Datorspråk som är avsedda för att skriva både icke-objektorienterade och objektorienterade program är C++ och Python.

Organiserad efter typ av data

redigera

Ett traditionellt icke objektorienterat program är organiserat i delprogram som kallas funktioner, exempelvis en funktion för inmatning, en annan för beräkning, en tredje för utmatning, och så en huvudfunktion som anropar de tre funktionerna i tur och ordning. Om man ska förändra programmet så att det hanterar en ny datatyp måste man förmodligen ändra i alla fyra av dessa funktioner, och måste då vara fullt insatt i alla funktionerna för att inte göra misstag. Det kan krävas att man lägger till många programrader som liknar de tidigare programraderna men inte är identiska.

I ett objektorienterat program organiseras programkoden istället i hög grad efter vilken typ av data det ska hanteras, precis som att man har olika verkstäder för plåt, elektronik, färg och motorer i ovanstående liknelse. Programkoden är uppdelad i klasser, vanligen en för varje typ av data som programmet ska hantera, och varje klass innehåller i sin tur programkod för olika funktioner (metoder) och variabelspecifikationer. Om man ska lägga till en ny typ av data behöver man bara lägga till en klass. Om man ska ändra något i programmet behöver man därmed i allmänhet ändra på färre ställen än vid icke objektorientering.

Färre kodrader vid komplicerade program

redigera

Ett enkelt program kräver i allmänhet fler kodrader om det är objektorienterat än om det inte är objektorienterat. Objektorientering möjliggör emellertid återanvändning av kod. Man behöver bara beskriva hur varje klass skiljer sig från andra klasser, istället för att återupprepa liknande kodrader i varje klass. Ett komplicerat program kan därmed få färre kodrader om det är objektorienterat.

Exempelvis kan ett datorprogram som simulerar en verkstad både ha en elektronikklass och en plåtklass. Båda klasserna kan ha en metod som heter lödkolv, och de båda lödkolvmetoderna kan återanvända samma komponenter, exempelvis en temperaturregulator, men också skilja sig åt.


Komplexa datastrukturer abstraheras bort

redigera

Om ett traditionellt program ska beskriva flera liknande entiteter, exempelvis registrera många användare av ett dataspel, brukar man skapa flera vektorer eller listor som beskriver användarnas egenskaper och tillstånd, exempelvis en vektor med samtliga användares namn, en med deras poängsummor, och en med deras respektive positioner på spelplanen. Om programmet är stort och komplext är det lätt hänt att en programmerare gör misstag och ändrar på fel plats i en vektor, i synnerhet om man har flera olika typer av entiteter (t.ex. olika typer av användare, både spelare och spelledare), där vissa saknar vissa egenskaper. Exempelvis har både spelare och spelledare namn men bara spelare har en poängsumma.

Alternativt lagrar man all data i en stor och komplex vektor som i sin tur består av så kallade structar, alltså en gruppering av variabler som kan ha olika datatyp. Structar var ett första steg mot objektorientering.

Om man ska kunna ändra ordning på spelarna och lägga till eller ta bort spelare brukar man vid traditionell programmering använda länkade listor, träd och andra komplicerade datastrukturer. Dynamiska pekare används då för att lagra minnesadressen till nästa variabel i listan, och det är mycket vanligt att programmerare gör misstag så att en pekare pekar på fel adress.

I ett objektorienterat program behöver programmeraren mer sällan hålla reda på vektorer och dynamiska pekare. Programkoden döljer detta för programmeraren, som oftast bara behöver hålla reda på enkla variabler för en entitet i taget. Man kan ha en heltalsvariabel som heter point för poäng och en strängvariabel som heter name för användarens namn. Dessa enkla variabler är grupperade i objekt, exempelvis ett objekt per användare som programmet ska registrera. Ett objekt liknar en struct, men det behöver sällan programmeraren tänka på. Ett objekt har, till skillnad från en struct, dessutom egna programfunktioner kallade metoder. Programkoden i objektets metoder är förhindrad från att påverka andra objekts variabler, och därmed är risken för misstag mindre.


Hur fungerar objektorienterad programmering?

redigera

Ett objekt kan lagra data samt innehålla de funktioner (metoder) som ska kunna appliceras på detta data. Om programmet ska hålla reda på exempelvis flera spelare skapar man ett nytt objekt för varje spelare, som beskriver spelarens egenskaper (attribut).

En klass är en beskrivning av olika objekt som har något gemensamt, exempelvis alla spelare av ett spel. Klassen kan betraktas som en mall för vilka data, metoder och meddelanden som ingår i alla objekt som tillhör den klassen. Ett objekt är i sin tur en instans av sin klass, det vill säga en kopia som kan ha modifierats något.

Klassens programkod specificerar metodernas programkod (inklusive konstruktorn), klassvariabler och instansvariabler.

Konstruktor

redigera

Objektet skapas (instansieras) av en metod som kallas konstruktor. I konstruktorn finns ritningen till objektet. Konstruktorn anger vilka instansvariabler som ska skapas och vilka värden de ska ha initialt. Alla klasser innehåller en konstruktor men har man inte definierat hur den ska se ut skapas ett tomt objekt, alltså ingenting.

Instansvariabler

redigera

Instansvariabler (kallas också attribut) lagrar data internt i objektet, och beskriver objektets egenskaper och aktuella tillstånd. Utrymme i datorns primärminne allokeras för instansvariablerna när ett objekt skapas (instantieras). Exempel är en spelares namn, poängställning, speltid och position på spelplanen. Dessa variabler är en del av objektet och är endast åtkomliga för objektets metoder. Instansvariabler specificeras i en definitionsklass.

Klassvariabler

redigera

Klassvariablerna instansieras inte, utan lagras bara i en uppsättning som är gemensam för alla klassens objekt, såsom antalet spelare.

Metoder

redigera

Metoderna beskrivs i klassen, och används inom klassens objekt för att behandla data. Metoderna bör vara privata, dvs bara åtkomliga inom respektive objekt för att förhindra att data påverkas av ett annat objekt av misstag. Undantaget är metoderna get och set som kan tillåtas användas för att andra objekt ska kunna kommunicera med objektet och ta reda på eller ändra vissa av dess instansvariabler.

Genom arv kan den programmerare som använder objektorienterad programmering konstruera nya klasser genom att låta dessa ärva egenskapen från någon annan basklass. Om man vill ändra ett dataspelsprogram så att det kan hantera en flera typer av objekt (exempelvis spelare och spelledare), skapar man vanligen en basklass (exempelvis användare) och ny klass för vardera typ av objekt, som utgör en beskrivning av vad som liknar och skiljer från basklassen.


Exempel på användandet av klasser (Java)

redigera

Kortspel

redigera

Om man ska göra till exempel ett kortspel så börjar man med att identifiera de objekt som används. Ett bra sätt är att leta substantiv.

  • Kortlek
  • Spelare

En kortlek innehåller kort.

Vi börjar med att skapa klassen Kort som ska innehålla:

  • instansvariabler (privata, tillgängliga bara inom klassen)
  • konstruktor som skapar kortet
  • metoder (verb som talar om vad som ska utföras)
Instansvariabler
redigera

Först bestämmer vi vilka variabler som behövs:

private static final String[] färglista = {"Klöver", "Ruter", "Hjärter", "Spader"};
private int färgnr, värdenr;

Variablerna är privata, bara åtkomliga i kort-klassen

Konstruktor
redigera

Konstruktorn skapar ett kort och vilket kort det blir måste man ange när konstruktorn anropas. Vi använder nr 0-3 för färgerna och 2-14 för värdet:

public Kort(int färg, int värde) {
 färgnr = färg;
 värdenr = värde;
}
Metoder
redigera

Och så skapar vi några metoder. Det enda man behöver är visa-metoder (get) för nåt annat gör man inte med ett kort:

public int getFärgnr () {
 return färgnr;
}
public int getVärdenr () {
 return värdenr;
}
public String toString () {
 return färglista[färgnr] + " " + värdenr;
}

Enda sättet att veta vilket kort det är är genom att ha metoder som är public. Alltså åtkomliga från andra klasser.

Man kan även ha set-metoder (ändra) för att ändra på en instansvariabel
toString är en metod för att kunna visa kortet som en sträng.

Kortlek

redigera

Man spelar inte kort med enstaka kort utan med en kortlek och därför skapar vi klassen Kortlek.

Instansvariabler
redigera

Här behövs en lista innehållande alla korten och en räknare nr som håller koll på vilket kort som ska ges:

private List<Kort>  högen = new LinkedList<Kort>();
private int nr;

variablerna är privata, bara åtkomliga i kortleks-klassen

Konstruktor
redigera

Konstruktorn skapar en kortlek:

public Kortlek() {
 for (int f=0;f<4;f++)
  for (int v=2;v<15;v++)
   högen.add(0,new Kort(f, v));
}
Metoder
redigera

Med en kortlek kan man blanda eller ge kort,

public void blanda() {
 nr = 0;
 Collections.shuffle(högen);
}		

public Kort geKort(){
 return högen.get(nr++);
}

Nu är kortleken skapad. Återstår att skapa en klass spelare och en Main-metod som sköter spelet.

För att använda kortleken:

Kortlek Leken = new Kortlek();
Leken.blanda();
Kort MittKort = Leken.geKort();

Nu innehåller variabeln MittKort ett kort.

För att titta på kortet använder man nån av metoderna som finns i kortklassen:

System.out.println(Mittkort.toString());