Nada

Föreläsning 9: Lös koppling, Java beans, miljöer mm

Programutvecklingsteknik består bland annat i konsten att lägga till nya finesser i gamla program och att få olika program att samarbeta. I objektterminologin motsvarar det begreppen arv och gränssnitt, i javaspråket är det extends och implements.

Lös koppling

Låt oss nu höja blicken och se på datasystem i stort. Ett sådant består av komponenter av följande slag: Arvs- och gränssnittstänkandet är genomgående med ISOs välkända sjulagers nätmodell som praktexempel. Det stora problemet har varit samarbetet mellan komponenterna. Den som säljer program har varit tvungen att utveckla många olika varianter för olika plattformar och att stödja många olika filformat, men nu är vi på väg mot en bättre värld, en värld där allt kan pluggas in!. Om man köpt ny hårdvara, till exempel en digitalkamera, kan man ofta räkna med att den kan anslutas till en vanlig port på hemdatorn och att hårdvaran då själv presenterar sej för operativsystemet. Man kan plugga in bredband hemma och det fungerar i princip utan ny hårdvara eller nya program. Ett javaprogram kan i princip pluggas in på vilken plattform som helst. Det som ännu inte är inpluggbart är datafiler. Det finns massor av format för bild, ljud, databaser etc och inkompatibiliteten är ofta avsiktlig för att försvåra konkurrens. Men med XML kan man faktiskt skriva inpluggningsbara, självbeskrivande datafiler!

En ofta bortglömd komponent i dom flesta datasystem är människorna. Olika användare bör helst kunna pluggas in utan att övriga komponenter byts. Det betyder att en kvinnlig datateknolog i Stockholm och en skäggig mulla i Teheran helst ska kunna köra samma program.

Java Beans och programmeringsmiljöer

Men situationen för den som vill sälja programkomponenter är inte så rolig. Man kan skriva hur väldokumenterade klasser som helst, men den vanliga programmeraren tycker att det är tillräckligt svårt att använda Suns standardklasser. Dessutom använder hon helst en grafisk programmeringsmiljö som JBuilder eller Forte för att få ihop programmet. Där har knappar, menyer och andra standardkomponenter små ikoner och man kan programmera all grafik med musklickningar -- ett klick på ikonen tar fram en egenskapslista där man väljer färg, font, storlek osv. När man kan programmera så enkelt tar det emot att skriva en massa kod för att kunna använda en inköpt komponent.

JavaBeans är en standard för programkomponenter som ska vara särskilt lättsålda eftersom dom installerar sej i själva utvecklingsmiljön genom att tala om för JBuilder vilka egenskaper dom har etc. Det gäller förstås även osynliga komponenter. Viggos program Stava skulle kunna tänkas vara en sådan komponent som många programmerare skulle kunna infoga.

På webben finns en utmärkt lektion om JavaBeans och en guidad tur i JBuilder.

CORBA

Med CORBA (Common Object Request Broker Architecture) kan program anropa varandra även om dom körs på olika datorer och är skrivna i olika språk. För det anropande klientobjektet ser det ut som ett vanligt metodanrop till ett vanligt objekt men i själva verket anropas en liten stubbe som översätter anropet till ett metaspråk och skickar vidare till en ORB (Object Request Broker). En ORB kan kommunicera med en ORB på en annan dator via protokollet IIOP (Internet Inter-ORB Protocol). Denna ORB letar upp rätt serverobjekt och låter en stubbe göra anropet i rätt språk. Sedan ska returvärdet gå samma väg tillbaka. Om klient och server finns på samma dator räcker det förstås med en ORB. Stubben på serversidan kallas också skelett.
diagram-orb_to_orb.gif

Ett program som ska anropa objekt via CORBA måste få veta vilka metoder som finns tillgängliga. Detta beskrivs med språket IDL (Interface Definition Language). IDL-kompilatorer som skapar stubbar från en IDL-fil finns för dom flesta programmeringsspråk. För att kompilera psyk.idl till Java används kommandot

      idlj -fall psyk.idl
    
Det här fungerar i javaversion 1.3 - gör module add jdk/1.3.1 annars. Resultatet av kompileringen är ett paket psyk av flera Java-filer. Där finns förutom stubbarna också några Helper-klasser, som hjälper till att översätta anropens objektparametrar till IIOP.

Designmönstren Proxy, Abstract factory, Decorator

CORBA-stubben är ett exempel på designmönstret Proxy (suppleant, ställföreträdare).
 ______         __________
| Kund |       /Gränssnitt\
|      |-------|          |
|______|       \__________/
                ^        ^
              __|__     _|___
             |Proxy|   |Real |
             |     |---|thing|
             |_____|   |_____|
Kunden tror sej anropa metoder i det verkliga objektet (Real thing) men det är bluffobjektet (Proxy) som tar emot anropen. Bluffobjektet skapar själv det verkliga objektet (om det inte redan finns) och skickar vidare anropen dit om inte proxyn klarar av dom.

Ett vanligt fall när proxymönstret används är när det tar tid att skapa the real thing - man kanske behöver läsa in en bildfil eller upprätta en nätförbindelse. Proxyn håller då ställningarna under tiden. En proxy för en ImageIcon ser ut så här (gränssnittet heter Icon).

 class ImageIconProxy implements Icon,Runnable                                  {
   private Icon realIcon = null                                                 ;
   private int width=50, height=40                                              ;
   private Component c /* komponenten ikonen bor i */                           ;
   public int getIconHeight()                                                   {
     if(realIcon==null) return height; else return realIcon.getIconHeight()     ;}
   public int getIconWidth()                                                    {
     if(realIcon==null) return width; else return realIcon.getIconWidth()       ;}
   public synchronized void paintIcon(final Component c,Graphics g,int x,int y) {
     this.c=c                                                                   ;
     if(realIcon!=null) realIcon.paintIcon(c, g, x, y)                          ;
     else                                                                       {
       g.drawRect(x, y, width-1, height-1)                                      ;
       g.drawString("Loading image...", x+20, y+20)                             ;
       new Thread(this).start()                                                 ;}}
   public void run()                                                            {
     realIcon = new ImageIcon(imageName)                                        ;
     c.repaint()                                                                ;}}	
Gränssnittet Icon kräver metoderna paintIcon, getIconWidth och getIconHeight. Första gången proxyns paint anropas startas en tråd som skapar den verkliga ikonen. Synkroniseringen behövs för att detta inte ska kunna göras dubbelt om två trådar anropar paintIcon.

Designmönstret Factory innebär att en klass, fabriksklassen, har fabriksmetoder för att skapa objekt av andra klasser, produktklasserna. En fabriksmetod createPnyxtr() ersätter helt enkelt new Pnyxtr() men ger bättre möjligheter att hålla koll på objekttillverkningen. Designmönstret Abstract factory är ett interface som implementeras av flera fabriksklasser, var och en med alla fabriksmetoder som anges i gränssnittet. Finessen är att man enkelt kan byta ut alla produktklasser mot andra produktklasser. Det utnyttjas till exempel för att alla javakomponenter (knappar, fönster etc) ska bytas mot andra som ser lite annorlunda ut när man byter från PC till Mac.

Designmönstret Decorator används när det finns en grundklass med massor av subklasser som skiljer sej genom vilka finesser som lagts till. Om det finns tio olika finesser blir det 1024 olika kombinationer och därmed 1024 olika klassnamn att hålla reda på. Men i stället kan man klara sej med tio subklasser om man låter dom ha en konstruktor där parametern är ett objekt ur grundklassen.

  Grund obj = new sub1(new sub2(new sub3())); // obj har nu finesser ur alla tre klasserna

Sidansvarig: <henrik@nada.kth.se>
Senast ändrad 10 mars 2003
Tekniskt stöd: <webmaster@nada.kth.se>