![[Datorn i utbildningen]](../bilder/diu6.jpg)
Under de senaste åren har det börjat stå allt klarare att de traditionella programspråken och programmeringsteknikerna är otillräckliga för att lösa dagens och morgondagens programmeringsproblem. Vi står inför en ny "programvarukris", liknande den i slutet av 60-talet.
Den största stötestenen är de moderna datorsystemens komplexitet. System som Macintosh, MS Windows och Presentation Manager (OS/2) är så komplicerade, att det är mycket svårt att göra tillämpningar med traditionella programmeringsverktyg och programspråk. Att systemen är komplicerade kan man inte göra så mycket åt. Tvärtom kommer detta att accentueras ännu mer i framtiden. Däremot kan man försöka förbättra de verktyg, tekniker och metoder som programmerarna använder.
Generellt kan sägas att för att komma ur den aktuella "programvarukrisen" behöver man verktyg, tekniker och metoder som gör komplexiteten hanterbar och som gör att programkod lätt kan återanvändas och ändras.
OOP är ett sätt att angripa dessa problem. Egenskaperna hos objektorienterade programspråk gynnar en modulär programuppbyggnad och underlättar konstruktion av återanvändbara och flexibla programkomponenter eller "byggklossar" (som kan byggas ut och modifieras).
OOP må vara mest känt av de nya "teknikerna", men det är inte ensamt herre på täppan. Det finns faktiskt två andra aspiranter som nog gärna vill ha med ett ord i laget, nämligen logikprogrammering och funktionell programmering. Vilka av de tre tronpretendenterna som till syvende och sist tar hem spelet, det är idag omöjligt att avgöra (det kanske t o m blir någon idag helt okänd outsider), men en sak står klar: Vi står inför ett s k paradigmskifte, liknande det som ägde rum när strukturerad programmering, efter hård debatt och många våndor, under 70-talet vann terräng och till slut övervann allt motstånd.
OOP används redan idag av flera programvaruhus. Alternativen, dvs logikprogrammering (PROLOG) och funktionell programmering (mest kända språk är ML - Meta Language), har sina främsta fotfästen vid universitet och forskningsinstitutioner och används relativt litet i "praktisk programmering". Detta behöver dock inte innebära att de är ute ur leken. Särskilt funktionell programmering har många förespråkare och företräden. Dess akilleshäl är att effektiv implementering förutsätter en annan datorarkitektur än den som dominerar idag. Skulle "parallella datorer" börja produceras i stor skala, då skulle också de funktionella programspråken snabbt kunna bli ett slagkraftigt alternativ.
Denna fråga är inte så enkel att besvara, åtminstone inte på några få rader, men låt oss ändå göra ett preliminärt försök - vi ska senare försöka reda ut begreppen närmare.
Precis som namnet antyder, utmärks objektorienterad programmering av att man arbetar med objekt. Ett objekt innehåller både data och de metoder som arbetar med objektets data. Olika objekt kommunicerar med varandra genom meddelanden, som aktiverar det mottagande objektets metoder. Olika objekt som har likadan uppsättning data och metoder sägs tillhöra samma klass.
Det ligger nära till hands att behandla klasser och objekt som abstrakta modeller av de "verkliga" objekt som man vill behandla i ett program. Ett objekt har vissa egenskaper (data) och kan utföra eller utsättas för olika saker (operationer på data): En sten har massa, vikt och volym, den kan falla, kastas osv; en geometrisk figur har form, omkrets och area, den kan ritas och vridas osv; en bankomat innehåller sedlar, med lämpliga operationer kan den fås att lämna ifrån sig några av dessa, etc.
När man programmerar i ett objektorienterat programspråk består en stor del av arbetet i att fundera ut vilka klasser man behöver och hur dessa skall vara relaterade till varandra.
Blev det hela så mycket klarare? Om inte: Hav tålamod! För att ge lite mer kött på benen ska vi börja med att titta på några objektorienterade programspråk och hur de växt fram, för att senare i mer detalj behandla de grundläggande OOP-begreppen och hur de hänger ihop.
Det första programspråket som introducerade objektorienterade tankegångar var Simula 67. När norrmännen Ole-Johan Dahl och Kristen Nygaard i mitten av 60-talet utvecklade Simula, var begreppet "objektorienterad programmering" ännu inte uppfunnet, och språkets upphovsmän använde det inte heller. Som namnet antyder var Simula 67 huvudsakligen avsett för simuleringar. Den viktigaste nyheten var införandet av klassbegreppet, som idag, i en eller annan form, återfinns i alla objektorienterade programspråk. I Simula 67 är en klass en typkonstruktion som innefattar såväl data som operationer på dessa, dvs data och operationer definieras tillsammans och blir intimt sammankopplade - de bildar en enda enhet.
Det programspråk som haft mest inflytande på den senare utvecklingen är Smalltalk, som skapades vid en av företagets Xerox forskningsavdelningar (Palo Alto Research Center - PARC) i mitten av 70-talet. Det mesta av den förhärskande objektorienterade terminologin härrör från Smalltalk. Dess inflytande sträcker sig dock betydligt längre än till begreppsapparaten. Här skall bara nämnas Smalltalks epokgörande programmeringsmiljö med överlappande fönster, mushantering, möjligheter att fritt blanda text och bitmappad grafik etc. Ur dessa koncept föddes först Apples Lisa och sedan dess framgångsrika efterföljare Macintosh.
Medan Simula har nått en relativt begränsad spridning (kompilatorer finns dock till PC-datorer), kan man idag få tag på Smalltalk-tolkar till de flesta lite mer allmänt förekommande datorsystem. Smalltalk används ofta för prototypning och simulering av komplicerade system.
Riktig genomslagskraft började de objektorienterade tankegångarna få först under 80-talet. Till en början kretsade intresset nästan uteslutande kring Smalltalk, men efterhand har idéerna kommit att aktualiseras och tillämpas i flera nya programspråk, samtidigt som allt fler gamla programspråk försetts med konstruktioner för objektorientering (s k "hybridspråk").
Till de nya objektorienterade programspråken hör Actor (som skapades för att underlätta skrivning av applikationer för MS Windows) och Eiffel. Till den ständigt växande skaran av "hybridspråk" hör C++ och Objective C, Object Pascal (på Macintosh) och Turbo Pascal (version 5.5) och Microsofts QuickPascal, liksom TopSpeed Pascal och Modula-2 (version 2.0).
Dataabstraktion är en viktig grundprincip i modern programmering. Om en datatyps egenskaper specificeras utifrån de värden som kan antas och de operationer som är tillåtna på densamma, erhålls en abstrakt datatyp. Så länge som relationerna mellan en sådan datatyp och omgivningen begränsas till de operationer som är definierade för datatypen, blir den aktuella implementeringen ointressant och kan ändras utan att det påverkar användningen av datatypen.
I de flesta objektorienterade programspråk realiseras dataabstraktionen med en klassdeklaration, där ingående data ("attribut") och operationer specificeras. De operationer som gäller för en klass kallas metoder (motsvarar underprogram i "traditionella" programspråk). Den fasta kopplingen mellan data och metoder kallas inkapsling.
Klassbegreppet kan lätt tillämpas på företeelser i vår vardag.
Antag att du har en IBM-kompatibel dator. Dess egenskaper beskrivs i datorns handbok. Denna handbok är gemensam för alla datorer av samma typ. Vi kan säga att datorn tillhör klassen "IBM-kompatibla datorer". I datorns handbok anges diverse "data" som gäller denna datorklass, samt hur datorer av IBM-kompatibel typ ska hanteras (metoder).
På samma sätt kan vi tala om klasserna "bilar", "flygplan", "båtar", "cyklar", "fåglar", "människor", "uranatomer", etc. Alla dessa klasser beskrivs av sina unika data och "metoder".
Ett objekt tillhör alltid en bestämd klass. Man brukar säga att ett enskilt objekt utgör en instans (ett exemplar) av en klass. Precis som man i icke-objektorienterade programspråk kan ha flera variabler av en viss datatyp, är det möjligt att ha flera instanser (exemplar, upplagor) av en viss klass.
Med klassexemplen ovan som utgångspunkt kan vi säga att din dator är ett objekt, eller en instans av klassen "IBM-kompatibla" datorer. På samma sätt utgör en viss bil ett objekt eller instans av klassen "bilar", fågeln som kvittrar (?) utanför ditt fönster en instans (exemplar) av klassen (arten) "fåglar" och du själv en instans av klassen "människor".
Ett objekts egenskaper bestäms av vilken klass det tillhör. Olika objekt som hör till samma klass har samma grundläggande egenskaper, dvs samma uppsättning metoder och data, även om värdena hos data kan skilja sig åt.
Klasser har många drag gemensamma med datatyper i icke objektorienterade programspråk. De kan betraktas som datastrukturer vilka även innehåller den kod (metoder) som opererar på data. Därför används ibland begreppet objekttyp som en synonym för klass.
För att utföra operationer på ett objekt, t ex ändra dess data, utnyttjas (anropas) objektets metoder, dvs de metoder som gäller den aktuella klassen. Eftersom metoderna ingår i objektet kan man se det hela som att man aktiverar objektet och ber detta att utföra operationer på sig självt. I objektorienterat språkbruk brukar man säga att man skickar ett meddelande till objektet och ber det utföra en handling.
Betrakta begreppen bilar, flygplan, båtar och tåg. Dessa har (åtminstone) en sak gemensam - de utgör transportmedel. Vi kan således betrakta transportmedel som en grundklass, med bilar osv som underklasser. Å andra sidan finns olika slags bilar, flygplan osv, dvs dessa kan i sin tur indelas i en eller flera underklasser. Vi får på detta sätt hierarkiskt ordnade relationer mellan de olika klasserna, ett familjeträd.
I det "verkliga livet", och särskilt i vetenskapliga sammanhang, är det mycket vanligt att på detta sätt klassificera olika företeelser utifrån deras gemensamma och särskiljande drag: växtriket (Linnés flora) och djurriket, litteratur och musik, grundämnena, organiska och oorganiska substanser, språk, idrottsgrenar, programspråk och operativsystem m m, allt kan indelas i undergrupper efter olika kriterier.
Objektorienterade programspråk ger möjlighet att relatera olika klasser till varandra på ett sätt som har många likheter med "det verkliga livets" familjeträd. Ett utmärkande drag hos klasser är nämligen att de kan ärva data och metoder från tidigare deklarerade klasser. Detta betyder att man med utgångspunkt från en enda, vanligen enkel klass (grundklassen), successivt kan skapa ner komplicerade och specifika klasser (underklasser eller härledda klasser). De nya klasserna (underklasserna) ärver grundklassens data och metoder, men kan också kompletteras med nya data och metoder och de ärvda metoderna kan också modifieras. Underklasserna kan sedan utgöra utgångspunkt för nya underklasser osv.
Arvsmekanismen medger således att man utifrån generella begrepp (grundklassen) kan bygga upp en klasshierarki (eller ett klassträd) av nya, allt mer specialiserade underklasser.
I vissa objektorienterade programspråk (såsom Turbo Pascal och Actor) kan en underklass endast ärva från en klass (en "barnklass" kan enbart ha en "förälderklass"). Andra objektorienterade språk (såsom C++ och Eiffel) tillåter multipla arv, dvs arv från två eller flera klasser (en "barnklass" kan enbart ha flera "föräldraklasser").
Ett objektorienterat programsystem byggs kring en uppsättning klasser som karakteriserar de objekt som ingår i systemet. En viktig aspekt vid konstruktionen av ett objektorienterat program består därför i att bestämma vilka klasser som behövs, vilka egenskaper dessa bör ha, samt hur olika klasser är relaterade till och växelverkar med varandra. Arvsmekanismen medger att redan existerande klasser återutnyttjas för att bilda mer komplexa klasser och utgör förmodligen den viktigaste enskilda mekanismen i ett objektorienterat programmeringsspråk.
Begreppet polymorfism kommer från grekiskan (polymorfi = månggestaltad). Med polymorfism menas att samma meddelande kan ge olika "svar" från objekt som tillhör olika klasser, dvs meddelandet väljer, under programkörningen, vilken metod som skall utföras.
Polymorfism åstadkoms med en mekanism som kallas sen (eller dynamisk) bindning.
För att klargöra innebörden av begreppet polymorfism utgår vi från ett exempel:
Antag att vi i en tillämpning arbetar med plana geometriska figurer (grundklassen). Underklasser kan då utgöras av t ex trianglar, rektanglar, cirklar och ellipser. Gemensamt för alla dessa är bl a att de har omkrets och area, men eftersom figurerna har olika form är det klart att omkrets och area måste beräknas på olika sätt för varje specifik figur. Polymorfism gör det möjligt att knyta olika metoder med samma namn till de olika geometriska figurerna och detta på ett sådant sätt att rätt metod automatiskt tillämpas på varje enskilt objekt. Annorlunda uttryckt: Man kan ha objekt, som tillhör olika, men besläktade klasser (trianglar, rektanglar, cirklar och ellipser), skicka samma meddelande (för att t ex beräkna omkretsen) och ändå få varje objekt att "svara" på ett sätt som är unikt för den underklass det tillhör, dvs objektet "vet" hur det skall beräkna sin egen omkrets (eller area).
För att ett programspråk ska kunna kallas objektorienterat, måste det tillhandahålla konstruktioner som understödjer dataabstraktion och inkapsling för att skapa klasser, en arvsmekanism så att klasser kan ärva egenskaper (data och metoder) från tidigare deklarerade klasser, samt polymorfism (via dynamisk bindning).
Om något av dessa element saknas, då kan heller inte programspråket betecknas som objektorienterat.
Både Ada och (standard-)Modula-2 understödjer dataabstraktion och inkapsling (inte via "klasser", men genom "paket" resp "moduler"), däremot saknar de såväl arvsmekanism som dynamisk bindning, varför de inte uppfyller kriterierna för objektorienterade programspråk (obs dock att objektorienterade versioner av Modula-2 finns).
Däremot behöver inte ett objektorienterat programspråk innehålla s k "överlagring" (eng. overloading), dvs möjlighet att utvidga användning av operatorer till att gälla nya typer av data (såsom i C++).
Industriell Datatekniks särtryck om Objektorientering (Ingenjörsförlaget 1989) är att rekommendera för den som önskar en lite fylligare introduktion till ämnet.
Betrand Meyers "Object-Oriented Software Construction" (Prentice Hall 1988) bör införskaffas av de som vill tränga in djupare i OOP:ns alla mysterier. Det är en mycket välskriven bok, som redan blivit något av en OOP-klassiker.
Om du själv vill försöka dig på att programmera objektorienterat är nog Turbo Pascal lättillgängligast, särskilt om du redan kan Pascal, men även TopSpeed Modula-2 duger fint. För de C-kunniga kan också C++ vara ett lämpligt försöksobjekt (!), även om C++ otvivelaktigt kräver mer än de två förstnämnda.
Martin F (i december -90)
Copyright © 1999 Martin Fahlgren
Epost:
uvvmfn@vasavux.educ.goteborg.se