© 1999-2003, Flemming Koch Jensen
Alle rettigheder forbeholdt
Introduktion til frameworks

Forudsætninger:

Det er en fordel, at man kender de patterns, der bliver nævnt i dette kapitel: Observer Pattern, Template Method, Strategy Pattern og Composite Pattern.

 

 

Hurtigere Et ønske vi altid har til systemudvikling, er at det skal gå hurtigere, og det vel at mærke uden at vi mister kvaliteten. En af de løsninger man har søgt at anvende på dette problem er genbrug. Generelt har objektorientering ikke kunnet levere genbrug i den størrelsesorden der har været lovet. Det skyldes mange faktorer som vi ikke her skal fordybe og i, men vi skal i stedet se hvordan vi kan lave genbrug.
Problem-domæne Frameworks er designet med henblik på genbrug. Et framework består af en række klasser, der retter sig mod et mere eller mindre snævert problem-domæne. Et eksempel på et framework er Swing. Swing har en lang række klasser man kan bruge til at opbygge en grafisk brugergrænseflade. Der er klasser der repræsenterer grafiske komponenter, der er klasser der indgår i eventhåndtering osv. Problem-domænet er grafiske brugergrænseflader; hvilket i framework-sammenhæng er et bredt problem-domæne.
Ikke kun klasse-bibliotek Et framework er ikke kun en samling af klasser - et klasse-bibliotek. Et framework angiver også hvordan man skal bruge klasserne - hvordan komponenterne skal arbejde sammen. I Swing er det f.eks. fastlagt hvordan eventhåndtering foregår, med listeners der modtager beskeder om de hændelser de interesseret i. Dette laves vha. Observer Pattern.
Genbrug af design Det er karakteristisk for frameworks at det samarbejde man skal indgå i, er beskrevet med design patterns. Et design pattern beskriver netop et genbrugeligt design, og på den måde bliver et framework ikke kun genbrug af implementation, men også genbrug af design.
Derfor kan man også se et framework som en skabelon for en applikation, en applikation der retter sig mod det pågældende problem-område.
Design patterns introducerer indirektion og abstraktion; hvilket giver os mulighed for at koble vore egne komponenter på frameworket - det giver os mulighed for at specialisere det. Set ud fra det perspektiv kan man også beskrive et framework som et "sprog" man bruger til at formulere sin applikation. Applikationen bliver et program skrevet i termer af frameworket.
Alt dette kommer desværre ikke uden omkostninger.
Lære det at kende Den første omkostning man må betale, er den tid det tager at lære frameworket at kende. Man kunne måske umiddelbart betragte dette som en generel omkostning, der er ved alting. Desværre er det ikke helt så uvæsentligt, da det kan være en større opgave at sætte sig ind i et framework. Hvis man prøver at bruge frameworket før man rigtig kender det, vil man opleve et stort behov for refactoring. Det skyldes at man ofte vil lave ting, der senere viser sig at være meget enklere på en anden måde. Enklere fordi dem der har lavet frameworket, allerede har tænkt det pågældende ind i frameworkets muligheder. Jeg har selv prøvet at vride armen om på et framework for at få det til at gøre som jeg ville, for senere at opdage, at det kunne være gjort ganske enkelt hvis jeg bare have kendt frameworket bedre. Hvis man derfor i et projekt vælger at bruge et framework, men ikke afsætter den fornødne tid til at lære det at kende, vil man blive skuffet, og i værste fald konkludere at frameworks ikke sparer tid!
Begræns-ninger Den anden pris man må betale er de begrænsninger som frameworket giver. Et framework retter sig mod et bestemt problem-domæne, og man vil nogle gange opleve at dette problem-domæne ikke 100% passer til det man skulle bruge. Enhver form for genbrug har et element af: "One size fit all", og frameworkets begrænsninger kan i visse situationer være irriterende. Her må man holde sig for øje, at man ikke kan få det hele. Man kan ikke både genbruge og få det præcist som man vil have det!

 

1. Hot Spots

Når man konstruerer en applikation er der en grænseflade mellem frameworket og de komponenter man selv laver. Disse "punkter" på frameworket, hvor de to mødes, kaldes hot spots. Der er grundlæggende to måder hvorpå disse hot spots kan være lavet: Enten ved nedarvning eller ved komposition.

 

1.1 Nedarvning

Whitebox Et framework der baserer sine hot spots på nedarvning kaldes et whitebox framework. Det skyldes at brugeren af frameworket nødvendigvis må have et nærmere kendskab til de klasser som han nedarver fra. Når man bruger nedarvning, specialiserer man frameworket ved at override metoder man nedarver fra klasser i frameworket. For at kunne gøre dette må man kende sammenhængen mellem metoderne i de pågældende klasser, og et vist kendskab til implementationen er derfor nødvendigt.
Metode er hot spot I forbindelse med whitebox frameworks anvendes ofte Template Method. I forbindelse med dette pattern vil en klasse i frameworket have en abstrakt hook-metode (den kan evt. have en default-implementation). Denne hook-metode optræder som et hot spot, og det er brugerens opgave at lave subklasser der implementerer denne metode
Figur 1:
Hot spot med hook-metode
Ved at lave subklassen, og implementere hook-metoden, specialiserer man frameworket.

 

1.2 Komposition

I eksemplet ovenfor blev der brugt Template Method, og den delegering der sker fra template-metoden til hook-metoden, er en delegering indenfor samme klasse. Med komposition sker en delegering, ved at kaldet af hook-metoden samtidig er en request til et andet objekt.
Eftersom Template Method og Strategy Pattern er paralleller, idet Strategy Pattern i al væsentlighed gør det samme som Template Method, ser man ofte Strategy Pattern anvendt i forbindelse med black box fremworks.
Blackbox Grunden til at kalder frameworks der baserer deres hot spots på komposition: blackbox frameworks, er at man i mindre grad har behov for at kende den indre opbygning af frameworket. Det eneste man skal gøre, er at lave komponenter, der overholder en interface-kontrakt ifht. frameworket. Hot spots er stadig metoder der skal implementeres, men de befinder sig nu i deres egne klasser.
Man kan illustrere det med at frameworket er et delsystem, hvor man sætter komponenter på de hot spots der tjener som "kontakter" til resten af systemet.
Figur 2:
Hot spot er "kontakter" hvor man tilslutter komponenter.
Her har vi lavet tre komponenter, der specialierer, og fuldender frameworket så det udgør en applikation. Metoderne, der håndterer de requests frameworket sender til de tre komponenter, er de tre hot spots.

 

1.3 Forholdet mellem whitebox og blackbox

Et framework er ikke et "enten eller" - det er ikke et whitebox framework eller et blackbox framework - det er en blanding!
Minimere nedarvning Det er karakteristisk for et framework at jo mindre modent det er, jo mere er hot spots baseret på nedarvning. Det er naturligvis at foretrække at brugeren behøver at kende så lidt som muligt til frameworkets implementation og indre opbygning. Det er derfor bedst at hot spots fungerer vha. komposition. Man vil ofte se at et framework, efterhånden som det udvikles og modnes på baggrund af de erfaringer man får, vil blive mere og mere kompositions-orienteret. Ikke dermed sagt, at et godt framework ikke har hot spots der baserer sig på nedarvning, men det vil være reduceret til et nødvendigt minimum.
AWT's gamle event-model F.eks. var den oprindelig event-model i AWT baseret på nedarvning. I Component-klassen var der erklæret en lang række metoder, der tog sig af diverse events, der måtte vedrøre det pågældende grafiske komponent. Når man ønskede at lave eventhåndtering, måtte man derfor nedarve fra den pågældende Component-klasse, override de relevante metoder, og lave en instans af den subklasse man havde konstrueret. Eftersom Java's GUI var, og er, opbygget efter Composite Pattern, bliver events propageret ned igennem composite-træet indtil nogen tager sig af dem. Tidligere var det derfor meget brugt at fange alle events i f.eks. en Frame-klasse, og lade den tage sig af eventhåndteringen af alle dens del-komponenter, fordi man ville undgå at lave et hav af subklasser til de komponenter klassen indeholdt. Dette bevirkede ofte at Frame-klassen antog et voldsomt omfang.
Modning Denne event-model blev brugt i JDK 1.0, men allerede i JDK 1.1 skiftede man til den vi kender i dag, som er baseret på Observer Pattern, med listeners. Det var et skift fra nedarvning til komposition, og det et godt eksempel på at en sådan udvikling er karakteristisk for frameworks, efterhånden som de modnes.