



<html>
<head>
  <title>javabog.dk -  - Hyppigt anvendte designm&oslash;nstre</title>
  <link rev="stylesheet" type="text/css" href="../typografi.css">
  <meta name="description" content="Lærebog i Java. Af Jacob Nordfalk. Udkommet hos Forlaget Globe">
  <meta name="keywords" content="designmønster, programmering, OOP, objekter, klasser, objektorienteret programmering, Java, JSP, lærebog, UML, IT">
</head>
<body bgcolor="#ffffff">



<a href='http://javabog.dk/'>javabog.dk</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel16.jsp'>&lt;&lt; forrige</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='indhold.jsp'>indhold</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel18.jsp'>n&aelig;ste &gt;&gt;</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kode/'>programeksempler</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='../index_VP.html'>om bogen</a>

<H1 CLASS="western" STYLE="">17 <a name='afsn17'></a>Hyppigt
anvendte designm&oslash;nstre</H1>
<DIV ID="Indholdsfortegnelse3">
  <P STYLE="margin-top: 0.3cm; margin-bottom: 0cm"><BR>
  </P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>17.1
  Proxy  274</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.1.1
  Simpelt eksempel: En stak, der logger kaldene  274</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.1.2
  Variationer af designm&oslash;nstret Proxy  275</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.1.3
  Eksempel: G&oslash;re data uforanderlige vha. Proxy  276</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.1.4
  Doven Initialisering/Virtuel Proxy  277</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.1.5
  Eksempel p&aring; Virtuel Proxy: En stak der f&oslash;rst oprettes,
  n&aring;r den skal bruges  277</FONT></FONT></P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>17.2
  Adapter  278</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.2.1
  Simpelt eksempel  278</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.2.2
  Anonyme klasser som adaptere  279</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.2.3
  Anonyme adaptere til at lytte efter h&aelig;ndelser  280</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.2.4
  Eksempel: F&aring; data til at passe ind i en JTable  281</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.2.5
  Ikke-eksempel: Adapter-klasserne  282</FONT></FONT></P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>17.3
  Iterator  283</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.3.1
  Iteratorer i Collections-klasserne  283</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.3.2
  Definere sin egen form for iterator  284</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.3.3
  Iteratorer i JDBC  284</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.3.4
  Iterator til at genneml&oslash;be geometriske figurer  285</FONT></FONT></P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>17.4
  Facade  286</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.4.1
  Eksempel: URL  286</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.4.2
  Eksempel: Socket og ServerSocket  286</FONT></FONT></P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>17.5
  Observat&oslash;r/Lytter  287</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.5.1
  Eksempel: H&aelig;ndelser  287</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.5.2
  Eksempel: Kalender  288</FONT></FONT></P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>17.6
  Dynamisk Binding  289</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.6.1
  JDBC og Dynamisk Binding  290</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.6.2
  Eksempel: Fortolkning af matematikfunktioner  292</FONT></FONT></P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>17.7
  Opgaver  293</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>17.8
  L&oslash;sninger  294</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.8.1
  Dataforbindelseslogger  294</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">17.8.2
  Designm&oslash;nstre i JDBC  294</FONT></FONT></P>
</DIV>

<P CLASS="kapiteloversigt-western">Det er en god id&eacute; at have
kigget i <a href='kapitel1.jsp#afsn1.1'>afsnit 1.1</a>, Lister og m&aelig;ngder, <a href='kapitel8.jsp'>kapitel 8</a>, Databaser (JDBC),
<a href='kapitel15.jsp#afsn15.9'>afsnit 15.9</a>, Introduktion til designm&oslash;nstre og <a href='kapitel16.jsp'>kapitel 16</a>, Skabende designm&oslash;nstre,
f&oslash;r man l&aelig;ser dette kapitel.</P>
<P CLASS="western" STYLE="">I dette kapitel
vil vi beskrive nogle af de designm&oslash;nstre, der ofte ses
anvendt i i standardbiblioteket og i lidt st&oslash;rre programmer.</P>
<P CLASS="western">Den overordnede id&eacute; i mange af
designm&oslash;nstrene er, som diskuteret i <a href='kapitel15.jsp#afsn15.9'>afsnit 15.9</a>, at give
id&eacute;er til, hvordan man afkobler (dvs. mindsker graden af
bindinger) mellem den del af programmet, som <I>bruger</I> nogle
objekter (kaldet klienten), og den del af programmet (dvs. de
klasser), der bruges.</P>
<H2 CLASS="western">17.1 <a name='afsn17.1'></a>Proxy</SPAN></H2>
<P CLASS="designm&oslash;nsteroverskrift-western">Problem: Et objekt,
der bliver brugt af klienten, skal nogen gange bruges lidt
anderledes, men ikke altid, s&aring; det er uhensigtsm&aelig;ssigt at
&aelig;ndre i klassen eller i klienten.</P>
<P CLASS="designm&oslash;nsteroverskrift-western">L&oslash;sning: Lav
en Proxy-klasse, der <I>lader</I> som om, den er det rigtige objekt,
og kalder videre i det rigtige objekt.</P>
<BLOCKQUOTE CLASS="definition-western">F&aring; metodekald til et
objekt til at g&aring; igennem et Proxy-objekt (mellem-objekt), der
modtager metodekald p&aring; vegne af (fungerer som en erstatning)
for det rigtige objekt</BLOCKQUOTE>
<P CLASS="western">Proxy kunne p&aring; dansk hedde &quot;str&aring;mand&quot;
eller &quot;mellemmand&quot;. Ordet brugtes oprindeligt i
banksektoren, men de fleste kender i dag kun ordet i forbindelse med
internettet: Har man ikke direkte forbindelse til internettet kan det
v&aelig;re n&oslash;dvendigt at konfigurere proxy-indstillingerne i
sin netl&aelig;ser, s&aring;dan at den sender foresp&oslash;rgslerne
til en proxy-server, der sp&oslash;rger videre ud p&aring;
internettet.</P>
<P CLASS="western">Oftest ved klienten ikke at den bruger en proxy.
N&aring;r proxyen bliver kaldt, vil den som regel delegere kaldet
videre til det andet objekt, men den kan ogs&aring; v&aelig;lge
f.eks.:</P>
<UL>
  <LI><P CLASS="western">at returnere med det samme og udf&oslash;re
  kaldet i baggrunden</P>
  <LI><P CLASS="western">at afvise kaldet (f.eks. ved at kaste en
  undtagelse)</P>
  <LI><P CLASS="western">at udf&oslash;re kaldet p&aring; en anden
  m&aring;de (f.eks. anderledes parametre)</P>
</UL>
<H3 CLASS="western">17.1.1 <a name='afsn17.1.1'></a>Simpelt eksempel: En stak, der logger
kaldene</H3>
<P CLASS="western">I stak-eksemplet fra <a href='kapitel15.jsp#afsn15.3.2'>afsnit 15.3.2</a> kunne det m&aring;ske
v&aelig;re rart under programudviklingen at logge de metodekald, der
bliver foretaget p&aring; stakken. 
</P>
<P CLASS="western">Vi kunne da lave en Proxy til stakken, der
udskriver kaldene:</P>
<PRE CLASS="kode-western">public class Staklogger implements Stak
{
<SPAN LANG="da-DK">  private StakMedNedarving2 rigtigeStak;</SPAN>

<SPAN LANG="da-DK">  public Staklogger(StakMedNedarving2 s) {  rigtigeStak = s; }</SPAN>

<SPAN LANG="da-DK">  public void l&aelig;gP&aring;(Object o)</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    System.out.print(&quot;Staklogger: l&aelig;gP&aring;(&quot;+o+&quot;)&quot;);</SPAN>
<SPAN LANG="da-DK">    <B>rigtigeStak.l&aelig;gP&aring;(o)</B>;</SPAN>
<SPAN LANG="da-DK">  }</SPAN>

<SPAN LANG="da-DK">  public Object tagAf()</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    Object o = <B>rigtigeStak.tagAf()</B>;</SPAN>
<SPAN LANG="da-DK">    System.out.print(&quot;Staklogger: tagAf() gav: &quot;+o);</SPAN>
<SPAN LANG="da-DK">    return o;</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<P CLASS="western">Der, hvor vi opretter objektet, pakker vi det
rigtige Stak-objekt ind i vores Staklogger:</P>
<PRE CLASS="kode-western">  Stak s = new Staklogger( new StakMedNedarving2() );</PRE><P CLASS="western">
Staklogger vil nu blive brugt p&aring; vegne af (i stedet for)
StakMedNedarving2, uden at klienten (resten af programmet) ved det.</P>
<P CLASS="western" ALIGN=CENTER><IMG SRC="bog18_html_m2f6ba223.gif" NAME="Grafik63" ALIGN=BOTTOM BORDER=0></P>
<P ALIGN=CENTER STYLE="margin-top: 0.11cm; margin-bottom: 0.11cm"><FONT SIZE=2 STYLE="font-size: 9pt"><I>Staklogger
er en Stak, der delegerer videre til en anden Stak (en
StakMedNedarving2)</I></FONT></P>
<P CLASS="western">Bem&aelig;rk, at i dette simple eksempel refererer
StakLogger til en StakMedNedarving2-klasse. Man kan g&oslash;re
StakLogger mere generelt anvendeligt ved at referere til
Stak-interfacet i stedet (jvf. <a href='kapitel15.jsp#afsn15.3'>afsnit 15.3</a>).</P>
<H3 CLASS="western">17.1.2 <a name='afsn17.1.2'></a>Variationer af designm&oslash;nstret Proxy</H3>
<P CLASS="western">Der findes nogle almindelige variationer af
Proxy-designm&oslash;nstret:</P>
<OL>
  <LI><P CLASS="western"><SPAN LANG="da-DK">Fjernproxy - bruges, n&aring;r
  man har brug for en lokal repr&aelig;sentation af et objekt, der
  ligger p&aring; en anden maskine. <a href='kapitel16.jsp#afsn16.8.2'>Afsnit 16.8.2</a> Dataforbindelse over netv&aelig;rk
  er et eksempel p&aring; dette. RMI (Remote Method Invocation)
  beskrevet i <a href='kapitel14.jsp#afsn14.3'>afsnit 14.3</a> anvender ogs&aring; dette princip.</SPAN></P>
  <LI><P CLASS="western">Cache - fungerer som proxy for et objekt med
  nogle omkostningsfulde metodekald. I de tilf&aelig;lde hvor en
  tidligere cachet returv&aelig;rdi fra metodekaldet kan bruges,
  foretages kaldet ikke, men den cachede v&aelig;rdi returneres i
  stedet (se <a href='kapitel16.jsp#afsn16.8.3'>afsnit 16.8.3</a>, Dataforbindelse, der cacher foresp&oslash;rgsler).</P>
  <LI><P CLASS="western">Adgangssproxy - bestemmer, hvad klienten kan
  g&oslash;re med det virkelige objekt. Et eksempel kan findes i n&aelig;ste
  afsnit.</P>
  <LI><P CLASS="western">Virtuel Proxy - udskyder oprettelsen af
  omkostningsfulde objekter, indtil der er brug for dem. Et eksempel
  kan findes i <a href='kapitel17.jsp#afsn17.1.5'>afsnit 17.1.5</a>.</P>
</OL>


<H3 CLASS="western" STYLE="">17.1.3 <a name='afsn17.1.3'></a>Eksempel:
G&oslash;re data uforanderlige vha. Proxy</H3>
<P CLASS="western">Dette eksempel viser, hvordan en samling af data
(af type Collection) kan g&oslash;res uforanderlig (dvs. at data i
objektet ikke kan &aelig;ndres, efter at objektet er oprettet - se
<a href='kapitel18.jsp#afsn18.1'>afsnit 18.1</a> for en n&aelig;rmere diskussion) ved hj&aelig;lp af en
Proxy.</P>
<P CLASS="western">Klassen bruges ved at pakke den oprindelige
samling ind i proxy-klassen (klassen UforanderligSamling vist
herunder) og derefter kun huske referencen til proxyen:</P>
<PRE CLASS="kode-western">    Collection d = new ArrayList();
<SPAN LANG="da-DK">    d.add(&quot;Hej&quot;);</SPAN>
<SPAN LANG="da-DK">    d.add(&quot;med&quot;);</SPAN>
<SPAN LANG="da-DK">    d.add(&quot;dig&quot;);</SPAN>
<SPAN LANG="da-DK">    ...</SPAN>

<SPAN LANG="da-DK">    d = new UforanderligSamling(d);</SPAN>
<SPAN LANG="da-DK"><I>    // herefter kan dataene ikke mere &aelig;ndres gennem d</I></SPAN></PRE><P CLASS="western">
UforanderligSamling delegerer alle foresp&oslash;rgsler videre til
den oprindelige samling, mens alle &aelig;ndringer afvises ved at
kaste undtagelsen UnsupportedOperationException.</P>
<PRE CLASS="kode-western">import java.util.*;
<SPAN LANG="da-DK">import java.io.*;</SPAN>

<SPAN LANG="da-DK">public class UforanderligSamling implements Collection, Serializable</SPAN>
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  private Collection c; <I>// til videredelegering</I></SPAN>

<SPAN LANG="da-DK">  UforanderligSamling(Collection c) {</SPAN>
<SPAN LANG="da-DK">    if (c==null) throw new NullPointerException();</SPAN>
<SPAN LANG="da-DK">    this.c = c;</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK"> </SPAN>
<SPAN LANG="da-DK"><I>  // videredelegering af kald, der ikke &aelig;ndrer samlingen c</I></SPAN>
<SPAN LANG="da-DK">  public int size()                           { return c.size(); }</SPAN>
<SPAN LANG="da-DK">  public boolean isEmpty()                    { return c.isEmpty(); }</SPAN>
<SPAN LANG="da-DK">  public boolean contains(Object o)           { return c.contains(o); }</SPAN>
<SPAN LANG="da-DK">  public boolean containsAll(Collection coll) { return c.containsAll(coll); } </SPAN>
<SPAN LANG="da-DK">  public Object[] toArray()                   { return c.toArray(); }</SPAN>
<SPAN LANG="da-DK">  public Object[] toArray(Object[] a)         { return c.toArray(a); }</SPAN>
<SPAN LANG="da-DK">  public String toString()                    { return c.toString(); }</SPAN>

<SPAN LANG="da-DK">  private static void fejl() { </SPAN>
<SPAN LANG="da-DK">    throw new UnsupportedOperationException(&quot;Denne samling kan ikke &aelig;ndres&quot;);</SPAN>
<SPAN LANG="da-DK">  }</SPAN>

<SPAN LANG="da-DK">  <I>// afvisning af kald, der &aelig;ndrer samlingen</I></SPAN>
<SPAN LANG="da-DK">  public void clear()                    { fejl(); }</SPAN>
<SPAN LANG="da-DK">  public boolean add(Object o)           { fejl(); return false; }</SPAN>
<SPAN LANG="da-DK">  public boolean remove(Object o)        { fejl(); return false; }</SPAN>
<SPAN LANG="da-DK">  public boolean addAll(Collection c)    { fejl(); return false; }</SPAN>
<SPAN LANG="da-DK">  public boolean removeAll(Collection c) { fejl(); return false; }</SPAN>
<SPAN LANG="da-DK">  public boolean retainAll(Collection c) { fejl(); return false; }</SPAN>

<SPAN LANG="da-DK"><I>  // iteratorer skal afvise &aelig;ndringer, men ellers fungere som c's iterator</I></SPAN>
<SPAN LANG="da-DK">  public Iterator iterator()</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    return new Iterator() {       <I>// anonym klasse, der implementerer Iterator</I></SPAN>
<SPAN LANG="da-DK">      Iterator i = c.iterator();  <I>// til videredelegering til c's iterator</I></SPAN>
<SPAN LANG="da-DK">      public boolean hasNext() { return i.hasNext(); }</SPAN>
<SPAN LANG="da-DK">      public Object next()     { return i.next(); }</SPAN>
<SPAN LANG="da-DK">      public void remove()     { fejl(); }</SPAN>
<SPAN LANG="da-DK">    };</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<P CLASS="western">I <a href='kapitel1.jsp#afsn1.6.6'>afsnit 1.6.6</a>, Uforanderlige samlinger, vises,
hvad der sker, n&aring;r man pr&oslash;ver at &aelig;ndre <SPAN LANG="da-DK">i
en uforanderlig samling. Ovenst&aring;ende svarer nemlig til det
Proxy-objekt man f&aring;r hvis man kalder
Collections.unmodifiableCollection().</SPAN></P>
<H3 CLASS="western" STYLE="">17.1.4 <a name='afsn17.1.4'></a>Doven
Initialisering/Virtuel Proxy</H3>
<P CLASS="western">Bruges en Proxy, kan oprettelsen af det andet
objekt egentlig godt udskydes, <I>indtil f&oslash;rste gang der er
brug for det</I>. S&aring; kalder man proxyen en Virtuel Proxy.
F&oslash;rste gang proxyen f&aring;r brug for at kalde videre i det
andet objekt, oprettes dette.</P>
<BLOCKQUOTE CLASS="definition-western">En Virtuel Proxy modtager
metodekald p&aring; vegne af et andet objekt, som det f&oslash;rst
opretter, n&aring;r der er brug for det</BLOCKQUOTE>
<P CLASS="western">Omkostningen ved at programmere en Virtuel Proxy
er, at hver gang objektet skal bruges, skal det f&oslash;rst tjekkes,
om objektet er blevet oprettet.</P>
<P CLASS="western">Der kan v&aelig;re flere grunde til at bruge en
Virtuel Proxy:</P>
<UL>
  <LI><P CLASS="western">Det rigtige objekt kan ikke oprettes endnu,
  f.eks. fordi det afh&aelig;nger af andre objekter, der ikke er klar
  endnu p&aring; oprettelsestidspunktet.</P>
  <LI><P CLASS="western">At oprette det rigtige objekt er dyrt i
  hukommelses- eller CPU-forbrug, og det er m&aring;ske slet ikke
  sikkert, at programmet kommer til at bruge objektet, s&aring; det er
  en fordel at udskyde oprettelsen.</P>
</UL>

<H3 CLASS="western">17.1.5 <a name='afsn17.1.5'></a>Eksempel p&aring; Virtuel Proxy: En stak
der f&oslash;rst oprettes, n&aring;r den skal bruges</H3>
<P CLASS="western">Her er en Virtuel Proxy til stakken fra <a href='kapitel15.jsp#afsn15.3.2'>afsnit 15.3.2</a>:</P>
<PRE CLASS="kode-western">public class VirtuelStak implements Stak
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  private Stak rigtigeStak;</SPAN>

<SPAN LANG="da-DK">  public void l&aelig;gP&aring;(Object o)</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK"><B>    if (rigtigeStak==null) rigtigeStak = new StakMedNedarving2();</B></SPAN>
<SPAN LANG="da-DK">    rigtigeStak.l&aelig;gP&aring;(o);</SPAN>
<SPAN LANG="da-DK">  }</SPAN>

<SPAN LANG="da-DK">  public Object tagAf()</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK"><B>    if (rigtigeStak==null) rigtigeStak = new StakMedNedarving2();</B></SPAN>
<SPAN LANG="da-DK">    return rigtigeStak.tagAf();</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<P CLASS="western">Der, hvor vi opretter objektet, bruger vi den
virtuelle stak:</P>
<PRE CLASS="kode-western">  Stak s = new VirtuelStak();</PRE><P CLASS="western">
Den virtuelle stak er nu oprettet, men ikke den rigtige stak. 
</P>
<P CLASS="western">Den oprettes f&oslash;rste gang l&aelig;gP&aring;()
kaldes:</P>
<PRE CLASS="kode-western">  ...
<SPAN LANG="da-DK">  s.l&aelig;gP&aring;(&quot;Hej&quot;);  <I>// f&oslash;rst her oprettes den rigtige stak</I></SPAN>
<SPAN LANG="da-DK">  s.l&aelig;gP&aring;(&quot;med&quot;);</SPAN>
<SPAN LANG="da-DK">  s.l&aelig;gP&aring;(&quot;dig&quot;);</SPAN></PRE>
<P CLASS="western">Der er egentlig ikke nogen specielt god grund til
at give en stak en Virtuel Proxy for noget s&aring; simpelt som en
stak - eksemplet er valgt, fordi det er simpelt og illustrativt.</P>
<H2 CLASS="western" STYLE="">17.2 <a name='afsn17.2'></a>Adapter</SPAN></H2>
<P CLASS="designm&oslash;nsteroverskrift-western">Problem: Et system
forventer et objekt af en bestemt type (der implementerer et bestemt
interface eller arver fra en bestemt klasse), men det objekt, man
&oslash;nsker at give til systemet, har ikke denne type.</P>
<P CLASS="designm&oslash;nsteroverskrift-western">L&oslash;sning:
Defin&eacute;r et Adapter-objekt af den type, som systemet forventer,
og lad Adapter-objektet delegere kaldene videre til det rigtige
objekt.</P>
<BLOCKQUOTE CLASS="definition-western">F&aring; et objekt til at
passe ind i et system ved at bruge et Adapter-objekt, der passer ind
i systemet, og som kalder videre i det rigtige objekt</BLOCKQUOTE>
<BLOCKQUOTE CLASS="definition-western">En Adapter fungerer som
omformer mellem nogle klasser</BLOCKQUOTE>
<P CLASS="western">I almindeligt sprogbrug er en adapter en lille
omformer, der g&oslash;r det muligt at forbinde et stik og en
fatning, der ellers ikke ville passe sammen. Som designm&oslash;nster
er en Adapter er en klasse, der fungerer som 'lim' mellem nogle
klasser og f&aring;r dem til at fungere sammen, selvom de ikke
umiddelbart er beregnet til at spille sammen.</P>
<P CLASS="western">Man kunne f.eks. i en virksomhed st&aring; i den
situation, at man har lavet en del af et program selv, men s&aring;
&oslash;nsker at udbygge programmet med nogle klasser, der er lavet
af en ekstern udvikler, som ikke kender noget til resten af
programmet. Virksomhedens egne klasser implementerer et givet
interface, men den del af programmet, der er lavet af den eksterne
udvikler, implementerer ikke dette interface. Hvad g&oslash;r man s&aring;?
</P>
<UL>
  <LI><P CLASS="western">En mulighed er at omskrive den del af
  programmet, der er lavet eksternt, s&aring;dan at klasserne kommer
  til at implementere virksomhedens eget interface. Det kan v&aelig;re
  en besv&aelig;rlig og tidskr&aelig;vende proces.</P>
  <LI><P CLASS="western">En anden mulighed er at lave en
  adapterklasse, som implementerer virksomhedens interface, og som s&aring;
  s&oslash;rger for at kalde videre i de klasser, der er lavet
  eksternt.</P>
</UL>
<P CLASS="western">Typisk implementerer en Adapter alts&aring; et
interface, der er kendt af klienten, og formidler adgang til en
klasse, der ikke er kendt af klienten.</P>
<H3 CLASS="western">17.2.1 <a name='afsn17.2.1'></a>Simpelt eksempel</H3>
<P CLASS="western">Lad os sige, at vi har nogle opgaver, der skal
udf&oslash;res, og at vi har defineret klassen Opgave, der tager sig
af disse opgaver:</P>
<PRE CLASS="kode-western">public class Opgave
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  public void udf&oslash;r() {</SPAN>
<SPAN LANG="da-DK"><I>    // noget kode her til at udf&oslash;re opgaven</I></SPAN>
<SPAN LANG="da-DK"><I>    // ...</I></SPAN>
<SPAN LANG="da-DK">    System.out.println(&quot;Opgave udf&oslash;rt.&quot;);</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<P CLASS="western">Nu viser det sig senere, at vi f&aring;r brug for
at k&oslash;re opgaven i en separat tr&aring;d. For at k&oslash;re
noget i en separat tr&aring;d skal interfacet Runnable (der
specificerer run()-metoden) implementeres. 
</P>
<P CLASS="western">Nu kunne vi selvf&oslash;lgelig &aelig;ndre
klassen Opgave, s&aring; den implementerede Runnable, men vi kunne
ogs&aring; v&aelig;lge at lave en Adapter, der f&aring;r Opgave til
at passe ind i Runnable:</P>
<PRE CLASS="kode-western" STYLE="">public class OpgaveRunnableAdapter implements Runnable
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  Opgave opg;</SPAN>
<SPAN LANG="da-DK">  OpgaveRunnableAdapter(Opgave o) { opg = o; }</SPAN>
<SPAN LANG="da-DK">  public void run() {</SPAN>
<SPAN LANG="da-DK">    opg.udf&oslash;r();              <I>// Overs&aelig;t kald af run() til kald af udf&oslash;r()</I></SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE><P CLASS="western">
Derefter kan vi passe et Opgave-objekt ind i en tr&aring;d:</P>
<PRE CLASS="kode-western">public class BenytOpgaveRunnableAdapter
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  public static void main(String[] args) {</SPAN>
<SPAN LANG="da-DK">    Opgave opgave = new Opgave();</SPAN>
<SPAN LANG="da-DK">    Runnable r = new OpgaveRunnableAdapter(opgave);</SPAN>
<SPAN LANG="da-DK">    Thread t = new Thread(r);</SPAN>
<SPAN LANG="da-DK">    t.start();</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<HR>
<PRE CLASS="kode-western">Opgave udf&oslash;rt.</PRE>
<P CLASS="western" ALIGN=CENTER><IMG SRC="bog18_html_1207a1dc.gif" NAME="Grafik35" ALIGN=BOTTOM BORDER=0></P>
<P ALIGN=CENTER STYLE="margin-top: 0.11cm; margin-bottom: 0.11cm"><FONT SIZE=2 STYLE="font-size: 9pt"><I>Vi
&oslash;nsker Opgave k&oslash;rt af en tr&aring;d, men Thread kr&aelig;ver,
at det <BR>implementerer Runnable, s&aring; vi laver en adapter til
Opgave.</I></FONT></P>
<H3 CLASS="western">17.2.2 <a name='afsn17.2.2'></a>Anonyme klasser som adaptere</H3>
<P CLASS="western">En anonym klasse er en klasse uden navn, som der
oprettes et objekt ud fra der, hvor den defineres. F.eks.:</P>
<PRE CLASS="ikke-javakode-western">public class KlasseMedAnonymKlasse
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  public void metode()</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    <I>// ... programkode for metode</I></SPAN>

<SPAN LANG="da-DK">    X objektAfAnonymKlasse <B>= new X()</B></SPAN>
<SPAN LANG="da-DK">    {</SPAN>
<SPAN LANG="da-DK">      void metodeIAnonymKlasse()</SPAN>
<SPAN LANG="da-DK">      {</SPAN>
<SPAN LANG="da-DK">        <I>// programkode</I></SPAN>
<SPAN LANG="da-DK">      }</SPAN>
<SPAN LANG="da-DK">      <I>// flere metoder og variabler i anonym klasse</I></SPAN>
<SPAN LANG="da-DK">    };</SPAN>

<SPAN LANG="da-DK">    <I>// mere programkode for metode</I></SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<P CLASS="western">Lige efter new angives det, hvad den anonyme
klasse arver fra, eller et interface, der implementeres (i dette
tilf&aelig;lde X). Man kan ikke definere en konstrukt&oslash;r til en
anonym klasse (den har altid standardkonstrukt&oslash;ren). Angiver
man nogle parametre ved new X(), er det parametre til superklassens
konstrukt&oslash;r.</P>
<P CLASS="western">Fordelen ved anonyme klasser er, at det tillades
p&aring; en nem m&aring;de at definere et specialiseret objekt
pr&aelig;cis, hvor det er n&oslash;dvendigt - det kan v&aelig;re
meget arbejdsbesparende.</P>
<P CLASS="western">Da adapterklasser er s&aring; sm&aring; og ofte
kun skal bruges et enkelt sted, definerer man dem ofte som anonyme
klasser.</P>
<H4 CLASS="western">Eksempel: Anonym RunnableAdapter</H4>
<P CLASS="western">Det f&oslash;lgende eksempel g&oslash;r det samme,
men i stedet for at bruge OpgaveRunnableAdapter anvendes en anonym
klasse, der implementerer Runnable og kalder videre i Opgave.</P>
<PRE CLASS="kode-western">public class BenytAnonymAdapter
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  public static void main(String[] args)</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    final Opgave opgave = new Opgave();</SPAN>

<SPAN LANG="da-DK">    Runnable r = new Runnable()</SPAN>
<SPAN LANG="da-DK">    {</SPAN>
<SPAN LANG="da-DK">      public void run()                      <I>// kr&aelig;ves af Runnable</I></SPAN>
<SPAN LANG="da-DK">      {</SPAN>
<SPAN LANG="da-DK">        opgave.udf&oslash;r();</SPAN>
<SPAN LANG="da-DK">      }</SPAN>
<SPAN LANG="da-DK">    };</SPAN>
<SPAN LANG="da-DK">    Thread t = new Thread(r);</SPAN>
<SPAN LANG="da-DK">    t.start();</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<H3 CLASS="western">17.2.3 <a name='afsn17.2.3'></a>Anonyme adaptere til at lytte efter
h&aelig;ndelser</H3>
<P CLASS="western">Vi har brugt masser af en bestemt slags
adapter-klasser i vores programmering: Til at lytte efter h&aelig;ndelser
og udf&oslash;re noget bestemt, n&aring;r h&aelig;ndelsen skete.
F.eks.:</P>
<PRE CLASS="kode-western">  private TextArea t1, t2;
<SPAN LANG="da-DK">  private Button kopierKnap;</SPAN>
<SPAN LANG="da-DK">  ...</SPAN>

<SPAN LANG="da-DK">  kopierKnap.addActionListener(new java.awt.event.ActionListener() {</SPAN>

<SPAN LANG="da-DK">    public void actionPerformed(ActionEvent e) {</SPAN>
<SPAN LANG="da-DK">      String s = t1.getText();</SPAN>
<SPAN LANG="da-DK">      t2.setText(s);</SPAN>
<SPAN LANG="da-DK">    }</SPAN>
<SPAN LANG="da-DK">  });</SPAN></PRE><P CLASS="western">
Her er den anonyme klasse en Adapter, der implementerer interfacet
ActionListener, der er kendt af klienten (kopierKnap), og formidler
adgang til klasser, der ikke er kendt af klienten (TextArea t1 og
t2). 
</P>


<H3 CLASS="western">17.2.4 <a name='afsn17.2.4'></a>Eksempel: F&aring; data til at passe ind i
en JTable</H3>
<P CLASS="western">Eksempelvis kunne det v&aelig;re, at vi havde en
liste af Kunde-objekter (defineret i <a href='kapitel16.jsp#afsn16.8'>afsnit 16.8</a>), som vi &oslash;nskede
at vise p&aring; sk&aelig;rmen i en JTable (beskrevet i <a href='kapitel6.jsp#afsn6.3.2'>afsnit 6.3.2</a>).</P>
<P CLASS="western">JTable ved selvf&oslash;lgelig ikke, hvordan den
skal vise Kunde-objekter - de &quot;passer&quot; ikke umiddelbart i
en JTable. Nu kunne vi naturligvis lave programmet om, s&aring;dan at
det var bedre indrettet til JTable, eller vi kunne kopiere indholdet
af Kunde-objekterne over i en datastruktur som JTable kunne genkende.</P>
<P CLASS="western">En smartere l&oslash;sning ville v&aelig;re at
lave en adapterklasse, der &quot;passer&quot; ind i JTable
(implementerer TableModel eller arver fra AbstractTableModel eller
DefaultTableModel), og som bruger den eksisterende Kunde-liste.</P>
<PRE CLASS="kode-western">import java.util.*;
<SPAN LANG="da-DK">import javax.swing.table.*;</SPAN>

<SPAN LANG="da-DK">public class KundelisteTableModelAdapter extends AbstractTableModel</SPAN>
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  private List liste;</SPAN>

<SPAN LANG="da-DK">  public KundelisteTableModelAdapter(List liste1) { liste = liste1; }</SPAN>

<SPAN LANG="da-DK">  public int getRowCount() { return liste.size(); }</SPAN>

<SPAN LANG="da-DK">  public int getColumnCount() { return 2; }  <I>// navn og kredit</I></SPAN>

<SPAN LANG="da-DK">  public String getColumnName(int kol)</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    return kol==0 ? &quot;Navn&quot; : &quot;Kredit&quot;;</SPAN>
<SPAN LANG="da-DK">  }</SPAN>

<SPAN LANG="da-DK">  public Object getValueAt(int r&aelig;kke, int kol)</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    Kunde k = (Kunde) liste.get(r&aelig;kke);</SPAN>
<SPAN LANG="da-DK">    return kol==0 ? k.navn : &quot;&quot;+k.kredit;</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE><P CLASS="western">
KundelisteTableModelAdapter er en Adapter, der implementerer
interfacet TableModel (gennem klassen AbstractTableModel), der er
kendt af klienten (JTable), og formidler adgang til klasser, der ikke
er kendt af klienten (listen af Kunde-objekter). 
</P>
<P CLASS="western">Her er et eksempel p&aring; brug af
KundelisteTableModelAdapter:</P>
<IMG SRC="bog18_html_m54ed048a.png" NAME="Grafik41" ALIGN=RIGHT BORDER=0>
<PRE CLASS="kode-western">import java.util.*;
<SPAN LANG="da-DK">import javax.swing.*;</SPAN>


<SPAN LANG="da-DK">public class BenytKundelisteTableModelAdapter</SPAN>
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  public static void main(String arg[])</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK"><I>    // Opret liste</I></SPAN>
<SPAN LANG="da-DK">    List liste = new ArrayList();</SPAN>
<SPAN LANG="da-DK">    liste.add( new Kunde( &quot;Jacob&quot;, -1899) );</SPAN>
<SPAN LANG="da-DK">    liste.add( new Kunde( &quot;S&oslash;ren&quot;,   600) );</SPAN>

<SPAN LANG="da-DK"><I>    // Opret vindue med tabel</I></SPAN>
<SPAN LANG="da-DK">    JFrame vindue = new JFrame();</SPAN>
<SPAN LANG="da-DK">    JTable tabel = new JTable();</SPAN>
<SPAN LANG="da-DK">    vindue.getContentPane().add(tabel);</SPAN>

<SPAN LANG="da-DK"><I>    // Lad tabel vise liste v.hj.a. adapteren</I></SPAN>
<SPAN LANG="da-DK">    tabel.setModel( new KundelisteTableModelAdapter( liste ));</SPAN>

<SPAN LANG="da-DK"><I>    // vis vindue</I></SPAN>
<SPAN LANG="da-DK">    vindue.setSize(200,100);</SPAN>
<SPAN LANG="da-DK">    vindue.setVisible(true);</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<H3 CLASS="western">17.2.5 <a name='afsn17.2.5'></a>Ikke-eksempel: Adapter-klasserne</H3>
<P CLASS="western">Uheldigvis er der i Java ogs&aring; nogle klasser,
der hedder adapter-klasserne. <I>Ingen af disse klasser er eksempler
p&aring; designm&oslash;nstret Adapter</I>!</P>
<P CLASS="western">Disse klasser tjener i stedet til at lette
programm&oslash;rens arbejde, n&aring;r han skal implementere et
h&aelig;ndelseslytter-interface, der har mere end en metode. I stedet
for at implementere interfacet direkte arver man fra en s&aring;kaldt
adapter-klasse, der har tomme implementationer for alle metoderne.</P>
<P CLASS="western">Eksempelvis, i stedet for at implementere
MouseListener:</P>
<PRE CLASS="kode-western">import java.awt.event.*;

<SPAN LANG="da-DK">public class Linjelytter <B>implements MouseListener</B></SPAN>
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  public void mousePressed(MouseEvent h&aelig;ndelse)  // kr&aelig;ves af MouseListener</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    System.out.println(&quot;Der blev trykkket med musen!&quot;);</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">  //--------------------------------------------------------------------</SPAN>
<SPAN LANG="da-DK">  //  Ubrugte h&aelig;ndelser (skal defineres for at implementere MouseListener)</SPAN>
<SPAN LANG="da-DK">  //--------------------------------------------------------------------</SPAN>
<SPAN LANG="da-DK">  public void mouseReleased(MouseEvent h&aelig;ndelse){} // kr&aelig;ves af MouseListener</SPAN>
<SPAN LANG="da-DK">  public void mouseClicked(MouseEvent event) {}  // kr&aelig;ves af MouseListener</SPAN>
<SPAN LANG="da-DK">  public void mouseEntered (MouseEvent event) {} // kr&aelig;ves af MouseListener</SPAN>
<SPAN LANG="da-DK">  public void mouseExited (MouseEvent event) {}  // kr&aelig;ves af MouseListener</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE><P CLASS="western">
kan man arve fra MouseAdapter (der implementerer MouseListener med
tomme metoder):</P>
<PRE CLASS="kode-western">import java.awt.event.*;

<SPAN LANG="da-DK">public class Linjelytter2 <B>extends MouseAdapter</B></SPAN>
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  public void mousePressed(MouseEvent h&aelig;ndelse)</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    System.out.println(&quot;Der blev trykkket med musen!&quot;);</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<P CLASS="western">Tilsvarende med de andre klasser i java.awt.event,
der ender p&aring; Adapter (ComponentAdapter, FocusAdapter,
KeyAdapter, MouseAdapter, MouseMotionAdapter og WindowAdapter): Ingen
af dem er en Adapter i designm&oslash;nster-henseende.</P>
<H2 CLASS="western" STYLE="">17.3 <a name='afsn17.3'></a>Iterator</SPAN></H2>
<P CLASS="designm&oslash;nsteroverskrift-western">Problem: Du er i
gang med at lave et system, som andre (klienter) skal anvende, hvor
de skal kunne genneml&oslash;be dine data. Du &oslash;nsker ikke, at
de skal kende noget til, hvordan data er repr&aelig;senteret i dit
system (f.eks. antal elementer eller deres placering i forhold til
hinanden).</P>
<P CLASS="designm&oslash;nsteroverskrift-western">L&oslash;sning:
Defin&eacute;r et hj&aelig;lpeobjekt (en Iterator), som klienten kan
bruge til at genneml&oslash;be data i dit system.</P>
<BLOCKQUOTE CLASS="definition-western">En Iterator er et hj&aelig;lpeobjekt
beregnet til at genneml&oslash;be data</BLOCKQUOTE>
<P CLASS="western">En Iterator har som minimum:</P>
<UL>
  <LI><P CLASS="western">en metode til at sp&oslash;rge, om der er
  flere elementer, og</P>
  <LI><P CLASS="western">en metode til at hente n&aelig;ste element</P>
</UL>
<P CLASS="western">En Iterator bruges i stedet for en t&aelig;llevariabel.
Fordelen ved at definere en Iterator er, at klienten <I>ikke beh&oslash;ver
at vide noget om strukturen af de data, der genneml&oslash;bes</I>. 
</P>
<H3 CLASS="western">17.3.1 <a name='afsn17.3.1'></a>Iteratorer i Collections-klasserne</H3>
<P CLASS="western">Iteratorer er flittigt brugt i
Collections-klasserne, idet alle datastrukturerne ligefrem har
metoden iterator(), der giver et objekt, der itererer gennem
elementerne.</P>
<P CLASS="western">Interfacet Iterator ser s&aring;ledes ud:</P>
<PRE CLASS="ikke-javakode-western">package java.util;

<SPAN LANG="da-DK">public interface Iterator {</SPAN>
<SPAN LANG="da-DK"><B>  boolean hasNext();</B>  <I>// om der er flere elementer </I></SPAN>
<SPAN LANG="da-DK"><B>  Object next();</B>      <I>// hent n&aelig;ste element</I></SPAN>
<SPAN LANG="da-DK">  void remove();</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE><P CLASS="western">
Man kan f.eks. genneml&oslash;be en Vector (eller en anden af
Collections-klasserne) med</P>
<PRE CLASS="kode-western">Vector samlingAfData;

<SPAN LANG="da-DK"><I>// inds&aelig;t nogle strenge i v</I></SPAN>
<SPAN LANG="da-DK">...</SPAN>

<SPAN LANG="da-DK">Iterator <B>i = samlingAfData.iterator()</B>;</SPAN>
<SPAN LANG="da-DK">while (<B>i.hasNext()</B>)</SPAN>
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  String s = (String) <B>i.next()</B>;</SPAN>
<SPAN LANG="da-DK">  ...</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE><P CLASS="western">
eller med en for-l&oslash;kke:</P>
<PRE CLASS="kode-western">for (Iterator i = v.iterator(); i.hasNext(); )
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  String s = (String) i.next();</SPAN>
<SPAN LANG="da-DK">  ...</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE><P CLASS="western">
Fordi vi bruger en Iterator, er vi afsk&aelig;rmet fra strukturen af
de data, der genneml&oslash;bes. Data beh&oslash;ver f.eks. ikke have
et bestemt indeks eller r&aelig;kkef&oslash;lge som i en Vector.
Ovenst&aring;ende eksempler virker lige s&aring; godt med en List
eller Set (en m&aelig;ngde).</P>
<P CLASS="western">Bem&aelig;rk, at klassen Iterator, som den er
defineret i Collections-klasserne, har noget, man normalt ikke
forbinder med en iterator, nemlig metoden remove(), der fjerner det
aktuelle element fra den underliggende samling af data.</P>

<H3 CLASS="western">17.3.2 <a name='afsn17.3.2'></a>Definere sin egen form for iterator</H3>
<P CLASS="western">Selvom forskellige former for iteratorer bruges
flittigt i standardbiblioteket, vil man nok sj&aelig;ldent komme ud i
at definere sin egen form for Iterator, da interfacet
java.util.Iterator d&aelig;kker langt de flestes behov.</P>
<BLOCKQUOTE CLASS="definition-western">Man vil meget sj&aelig;ldent
selv definere en ny form for Iterator, med mindre man er i gang med
at programmere et programbibliotek 
</BLOCKQUOTE>
<H3 CLASS="western">17.3.3 <a name='afsn17.3.3'></a>Iteratorer i JDBC</H3>
<P CLASS="western">N&aring;r vi behandler svaret p&aring; en
foresp&oslash;rgsel til en database, sker det ved at iterere gennem
svar-tabellen r&aelig;kke for r&aelig;kke. 
</P>
<P CLASS="western">Det g&oslash;res med et ResultSet-objekt.
Interfacet ResultSet ser s&aring;ledes ud:</P>
<PRE CLASS="ikke-javakode-western">package java.sql;

<SPAN LANG="da-DK">public interface ResultSet {</SPAN>
<SPAN LANG="da-DK">  boolean next() throws SQLException;</SPAN>
<SPAN LANG="da-DK">  boolean previous() throws SQLException;</SPAN>

<SPAN LANG="da-DK">  boolean isFirst() throws SQLException;</SPAN>
<SPAN LANG="da-DK">  boolean isLast() throws SQLException;</SPAN>
<SPAN LANG="da-DK">  boolean first() throws SQLException;</SPAN>
<SPAN LANG="da-DK">  boolean last() throws SQLException;</SPAN>

<SPAN LANG="da-DK">  int getRow() throws SQLException;</SPAN>
<SPAN LANG="da-DK">  boolean absolute( int row ) throws SQLException;</SPAN>
<SPAN LANG="da-DK">  boolean relative( int rows ) throws SQLException;</SPAN>

<SPAN LANG="da-DK">  ... mange andre metoder til bl.a. at afl&aelig;se/opdatere r&aelig;kker</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<P CLASS="western">Eksempel p&aring; brug:</P>
<PRE CLASS="kode-western">// foresp&oslash;rgsler

<SPAN LANG="da-DK">ResultSet rs = stmt.executeQuery(&quot;SELECT navn, kredit FROM kunder&quot;);</SPAN>
<SPAN LANG="da-DK">while (<B>rs.next()</B>)</SPAN>
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  String navn = <B>rs.getString(&quot;navn&quot;)</B>;</SPAN>
<SPAN LANG="da-DK">  double kredit = <B>rs.getDouble(&quot;kredit&quot;)</B>;</SPAN>
<SPAN LANG="da-DK">  System.out.println(navn+&quot; &quot;+kredit);</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE><P CLASS="western">
Her er metoderne til at sp&oslash;rge, om der er flere elementer, og
til at hente n&aelig;ste element sl&aring;et sammen til &eacute;n
metode, nemlig next(). 
</P>
<P CLASS="western">Vi (klienten) beh&oslash;ver ikke at vide noget
om, hvordan data er repr&aelig;senteret, og heller ikke om alle data
hentes p&aring; &eacute;n gang eller lidt efter lidt efterh&aring;nden
som vi kalder next().</P>

<H3 CLASS="western">17.3.4 <a name='afsn17.3.4'></a>Iterator til at genneml&oslash;be
geometriske figurer</H3>
<P CLASS="western">De funktioner, Java har til at manipulere med
todimensionale geometriske figurer (Java2D - beskrevet i <a href='kapitel5.jsp'>kapitel 5</a>) i
pakken java.awt.geom, baserer sig kraftigt p&aring; iteratorer. 
</P>
<P CLASS="western">Der findes disse grundl&aelig;ggende geometriske
figurer:</P>
<UL>
  <LI><P CLASS="western">Rektangler - Rectangle2D og RoundRectangle2D</P>
  <LI><P CLASS="western">Linjer - Line2D (en ret linje), CubicCurve2D
  (en linje, der er buet efter et ankerpunkt) og QuadCurve2D (en
  linje, der er buet efter to ankerpunkter)</P>
  <LI><P CLASS="western">Ellipse2D og Arc2D (buestykke)</P>
</UL>
<P CLASS="western">F&aelig;lles for dem alle er, at de best&aring;r
af (buede eller rette) linjestykker (en firkant best&aring;r f.eks.
af fire rette linjestykker), og alle figurerne kan, selvom de er ret
forskelligt repr&aelig;senteret indeni, returnere en Iterator til at
genneml&oslash;be linjestykkerne i figuren. 
</P>
<P CLASS="western">Denne iterator ser s&aring;ledes ud:</P>
<PRE CLASS="ikke-javakode-western">package java.awt.geom;

<SPAN LANG="da-DK">public interface PathIterator</SPAN>
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK"><I>  // om iterationen er n&aring;et gennem alle linjestykkerne</I></SPAN>
<SPAN LANG="da-DK"><B>  public boolean isDone();</B></SPAN>

<SPAN LANG="da-DK"><I>  // g&aring; til n&aelig;ste linjesegment</I></SPAN>
<SPAN LANG="da-DK"><B>  public void next();</B></SPAN>

<SPAN LANG="da-DK"><I>  // l&aelig;gger data f&aring;r det aktuelle linjestykke ind i variablen segment</I></SPAN>
<SPAN LANG="da-DK"><B>  public int currentSegment(double[] segment);</B></SPAN>

<SPAN LANG="da-DK">  ... flere metoder</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE><P CLASS="western">
N&aring;r Java2D skal kombinere flere geometriske figurer til en ny
figur, sker det ved, at den genneml&oslash;ber figurernes
linjesegmenter v.hj.a. iteratoren og derp&aring; opbygger det
kombinerede geometriske objekt.</P>
<P CLASS="western">Det sker f.eks. i klassen GeneralPath, der
repr&aelig;senterer en vilk&aring;rlig geometrisk figur, der f.eks.
kan bygges op ved at kombinere andre geometriske figurer:</P>
<PRE CLASS="kode-western">  GeneralPath figur = new GeneralPath();
<SPAN LANG="da-DK">  figur.append( new Line2D.Float(0, 0, 100, 100), false );</SPAN>
<SPAN LANG="da-DK">  figur.append( new CubicCurve2D.Float(0, 0, 80, 15, 10, 90, 100, 100), false );</SPAN>
<SPAN LANG="da-DK">  figur.append( new Arc2D.Float(-30, 0, 100, 100, 60, -120, Arc2D.PIE), false );</SPAN></PRE><P CLASS="western">
Hver gang append() bliver kaldt med en figur, findes f&oslash;rst en
PathIterator p&aring; figuren, denne genneml&oslash;bes derefter, og
linjestykkerne f&oslash;jes til GeneralPath-objektet.</P>
<H2 CLASS="western" STYLE="">17.4 <a name='afsn17.4'></a>Facade</SPAN></H2>
<P CLASS="designm&oslash;nsteroverskrift-western">Problem: Et s&aelig;t
af besl&aelig;gtede objekter er indviklede at bruge, og der er brug
for en simpel gr&aelig;nseflade til dem.</P>
<P CLASS="designm&oslash;nsteroverskrift-western">L&oslash;sning:
Defin&eacute;r et hj&aelig;lpeobjekt, en <I>Facade</I><SPAN STYLE="font-style: normal">,
der g&oslash;r objekterne lettere at bruge.</SPAN></P>
<BLOCKQUOTE CLASS="definition-western">En Facade giver en
simplificeret gr&aelig;nseflade til en gruppe delsystemer eller til
et indviklet system</BLOCKQUOTE>
<P CLASS="western">En Facade er alts&aring; et objekt, der giver en
&quot;brugergr&aelig;nseflade&quot; til nogle andre objekter og
dermed forenkler brugen af disse objekter.</P>

<H3 CLASS="western">17.4.1 <a name='afsn17.4.1'></a>Eksempel: URL</H3>
<P CLASS="western">I pakken java.net er klassen URL en Facade for en
r&aelig;kke andre klasser, der kan h&aring;ndtere en lang r&aelig;kke
protokoller, bl.a. HTTP, FTP, e-post og lokale filer (se eksempler i
<a href='kapitel18.jsp#afsn18.4.3'>afsnit 18.4.3</a>). 
</P>
<P CLASS="western">Men for klienten er URL-klassen ekstrem nem at
bruge, f.eks. kan klienten hente en hjemmeside ned i en datastr&oslash;m
med:</P>
<PRE CLASS="kode-western">  URL u = new URL(&quot;http://java.sun.com/&quot;);
<SPAN LANG="da-DK">  InputStream is = u.openStream();</SPAN>
<SPAN LANG="da-DK">  ...</SPAN></PRE><P CLASS="western">
Facaden skjuler hele processen for os og letter os dermed fra byrden
med at forst&aring;, hvordan klasserne og kommunikationen fungerer
inde bagved: Internt bruger URL et InetAddress-objekt til at
repr&aelig;sentere v&aelig;rtsmaskinens IP-adresse, og den bruger et
URLStreamHandler-objekt til at h&aring;ndtere protokollen (i dette
tilf&aelig;lde HTTP-protokollen). Dette URLStreamHandler-objekt
fabrikerer en URLConnection, og URL kalder videre i dette
URLConnection-objekt, n&aring;r vi kalder openStream().</P>
<P CLASS="western"><SPAN LANG="da-DK">Se <a href='kapitel12.jsp#afsn12.7'>afsnit 12.7</a> for en
beskrivelse af netv&aelig;rksklasserne i standardbiblioteket.</SPAN></P>

<H3 CLASS="western">17.4.2 <a name='afsn17.4.2'></a>Eksempel: Socket og ServerSocket</H3>
<P CLASS="western">L&aelig;ser man dokumentationen til klasserne
Socket (der repr&aelig;senterer en forbindelse til en bestemt maskine
over netv&aelig;rket p&aring; en bestemt port og som klienter bruger
til at forbinde sig til v&aelig;rtsmaskiner med) og ServerSocket (der
repr&aelig;senterer en port p&aring; en v&aelig;rtsmaskine der er
&aring;ben for indkommende forbindelser), finder man ud af, at de
begge faktisk er facader til klassen SocketImpl. 
</P>
<P CLASS="western">Denne konstruktion skyldes, at det p&aring;
styresystemets niveau er n&aelig;sten de samme kald, der skal ske for
en Socket og en ServerSocket, og de varetages derfor af den samme
klasse (SocketImpl). Socket og en ServerSocket bruger alts&aring;
begge SocketImpl til at varetage den egentlige netv&aelig;rkskommunikation.
</P>
<P CLASS="western">Designerne til Javas standardbibliotek har anvendt
designm&oslash;nstret Facade for at g&oslash;re det simplere at lave
netv&aelig;rkskommunikation: De har delt funktionaliteten i
SocketImpl op i to letforst&aring;elige klasser (Socket og en
ServerSocket) til de to m&aring;der, den kan bruges p&aring;.</P>

<H2 CLASS="western" STYLE="">17.5 <a name='afsn17.5'></a>Observat&oslash;r/Lytter</SPAN></H2>
<P CLASS="designm&oslash;nsteroverskrift-western">Problem: Et objekt
skal kunne underrette nogle andre objekter om en eller anden &aelig;ndring
eller h&aelig;ndelse, men det er ikke hensigtsm&aelig;ssigt, at
objektet kender direkte til de andre objekter.</P>
<P CLASS="designm&oslash;nsteroverskrift-western">L&oslash;sning: Lad
lytterne (observat&oslash;rerne) implementere et f&aelig;lles
interface (eller arve fra en f&aelig;lles superklasse) og registrere
sig hos det observable (observerbare) objekt. Det observable objekt
kan herefter underrette lytterne gennem interfacet, n&aring;r der er
brug for det.</P>
<P CLASS="western">Designm&oslash;nstret Observat&oslash;r (eng.:
Observer) kaldes ogs&aring; Abonnent (eng.: Publisher-Subscriber)
eller lytter (eng.: Listener).</P>
<H3 CLASS="western">17.5.1 <a name='afsn17.5.1'></a>Eksempel: H&aelig;ndelser</H3>
<P CLASS="western">Det mest kendte eksempel p&aring;
Observat&oslash;r-designm&oslash;nstret er h&aelig;ndelsesh&aring;ndteringen
i grafiske brugergr&aelig;nseflader.</P>
<P CLASS="western">N&aring;r man vil lytte efter museh&aelig;ndelser,
opretter man en klasse, der implementerer MouseListener-interfacet
(observat&oslash;ren):</P>
<PRE CLASS="kode-western">import java.awt.*;
<SPAN LANG="da-DK">import java.awt.event.*;</SPAN>

<SPAN LANG="da-DK">public class Muselytter implements MouseListener</SPAN>
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  public void mousePressed(MouseEvent h&aelig;ndelse)  // kr&aelig;ves af MouseListener</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    Point trykpunkt = h&aelig;ndelse.getPoint();</SPAN>
<SPAN LANG="da-DK">    System.out.println(&quot;Mus trykket ned i &quot;+trykpunkt);</SPAN>
<SPAN LANG="da-DK">  }</SPAN>

<SPAN LANG="da-DK">  public void mouseReleased(MouseEvent h&aelig;ndelse)  // kr&aelig;ves af MouseListener</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    Point slippunkt = h&aelig;ndelse.getPoint();</SPAN>
<SPAN LANG="da-DK">    System.out.println(&quot;Mus sluppet i &quot;+slippunkt);</SPAN>
<SPAN LANG="da-DK">  }</SPAN>

<SPAN LANG="da-DK">  public void mouseClicked(MouseEvent h&aelig;ndelse)  // kr&aelig;ves af MouseListener</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    System.out.println(&quot;Mus klikket i &quot;+h&aelig;ndelse.getPoint());</SPAN>
<SPAN LANG="da-DK">  }</SPAN>

<SPAN LANG="da-DK">  //--------------------------------------------------------------------</SPAN>
<SPAN LANG="da-DK">  //  Ubrugte h&aelig;ndelser (skal defineres for at implementere MouseListener)</SPAN>
<SPAN LANG="da-DK">  //--------------------------------------------------------------------</SPAN>
<SPAN LANG="da-DK">  public void mouseEntered (MouseEvent event) {}  // kr&aelig;ves af MouseListener</SPAN>
<SPAN LANG="da-DK">  public void mouseExited (MouseEvent event) {}  // kr&aelig;ves af MouseListener</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<P CLASS="western">Man skal registrere lytteren (observat&oslash;ren)
ved at kalde metoden addMouseListener(lytter) p&aring; den grafiske
komponent, der sender h&aelig;ndelserne (den observable):</P>
<PRE CLASS="kode-western">import java.applet.*;
<SPAN LANG="da-DK">public class LytTilMusen extends Applet</SPAN>
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  public LytTilMusen()</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    Muselytter <B>lytter = new Muselytter()</B>;</SPAN>
<SPAN LANG="da-DK">    <B>this.addMouseListener(lytter)</B>;  <I>// tilf&oslash;j lytteren til er appletten selv</I></SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE><P CLASS="western">
N&aring;r man senere klikker med musen, bliver metoder i lytteren
kaldt.</P>

<H3 CLASS="western">17.5.2 <a name='afsn17.5.2'></a>Eksempel: Kalender</H3>
<P CLASS="western">Forestil dig et program, der skal fungere som en
f&aelig;lles kalender for en forening, der udbyder forskellige
foredrag. 
</P>
<P CLASS="western">Kalenderen indeholder en liste over foredragene,
og medlemmerne af foreningen kan tilmelde sig de forskellige foredrag
efter &oslash;nske.</P>
<P CLASS="western">Hvis der sker &aelig;ndringer i planen, skal kun
de interesserede medlemmer have besked, dvs. de, som har tilmeldt sig
et givent foredrag.</P>
<P CLASS="western">Det kan implementeres ved at lave et
foredragsobjekt, som indeholder en liste af registrerede lyttere.
Objektet har metoder til at tilf&oslash;je og fjerne lyttere og til
at l&oslash;be listen igennem og sende beskeder, n&aring;r det er
n&oslash;dvendigt. 
</P>
<P CLASS="western">Her er en skitse til et klassediagram:</P>
<P CLASS="western" ALIGN=CENTER><IMG SRC="bog18_html_m396caad1.gif" NAME="Grafik67" ALIGN=BOTTOM BORDER=0></P>


<H2 CLASS="western" STYLE="">17.6 <a name='afsn17.6'></a>Dynamisk
Binding</SPAN></H2>
<P CLASS="designm&oslash;nsteroverskrift-western">Problem: Programmet
skal senere kunne udvides til at bruge nogle flere klasser, uden at
programmet skal skrives om.</P>
<P CLASS="designm&oslash;nsteroverskrift-western">L&oslash;sning:
Defin&eacute;r et f&aelig;lles interface (eller superklasse) for
klasserne, og s&oslash;g efter egnede klasser p&aring;
k&oslash;retidspunktet, indl&aelig;s dem og brug dem.</P>
<BLOCKQUOTE CLASS="definition-western">Indl&aelig;s klasser dynamisk
under k&oslash;rslen</BLOCKQUOTE>
<P CLASS="western">Dynamisk Binding (eller Dynamisk L&aelig;nkning - 
eng.: Dynamic Linkage) g&aring;r ud p&aring; at indl&aelig;se klasser
dynamisk, <I>efter</I> at programmet er startet. Det er en meget
kraftfuld mekanisme der tillader &quot;plug-ins&quot;, dvs. at
programdele kan f&oslash;jes til programmet, efterh&aring;nden som
der er behov for dem, og som m&aring;ske er produceret af nogle helt
andre end dem, der oprindeligt skrev programmet.</P>
<P CLASS="western">I Java indl&aelig;ses en klasse dynamisk med et
kald til Class.forName(), der tager en streng med et klassenavn som
parameter. 
</P>
<P CLASS="western">F.eks. indl&aelig;ser man Vector-klassen og
opretter et objekt med:</P>
<PRE CLASS="kode-western">  Class klassen = Class.forName(&quot;java.util.Vector&quot;);
<SPAN LANG="da-DK">  Object objektet = klassen.newInstance();</SPAN></PRE>
<P CLASS="western">Dette foruds&aelig;tter, at klasserne findes der,
hvor systemet plejer at lede (ellers kan man definere sin egen
ClassLoader som beskrevet i <a href='kapitel11.jsp#afsn11.4.3'>afsnit 11.4.3</a>, Indl&aelig;se klasser fra filsystemet).</P>
<P CLASS="western">Herunder er beskrevet to konkrete eksempler p&aring;
Dynamisk Binding. Et tredje eksempel (URL-klassen) diskuteres i
<a href='kapitel18.jsp#afsn18.4.5'>afsnit 18.4.5</a>.</P>


<H3 CLASS="western">17.6.1 <a name='afsn17.6.1'></a>JDBC og Dynamisk Binding</H3>
<P CLASS="western">JDBC anvender Dynamisk Binding til at h&aring;ndtere
drivere for de forskellige databaser. Det tillader enhver
databaseleverand&oslash;r at levere drivere, og de vil umiddelbart
passe ind i JDBC.</P>
<P CLASS="western">Kigger man i pakken java.sql (se
javadokumentationen), kan man f&aring; en id&eacute; om, hvordan det
g&oslash;res. Herunder er en forsimplet udgave af implementationen af
JDBC, der illustrerer princippet (eksemplet kan ikke k&oslash;res,
det skal mere ses som en illustration af JDBC's brug af  Dynamisk
Binding).</P>
<P CLASS="western">DriverManager har en intern liste af drivere. N&aring;r
DriverManager.getConnection() kaldes, kalder den en metode i hver af
sine indl&aelig;ste drivere for at finde en, der passer. Drivere, der
ikke passer til den URL, der beskriver forbindelsen, signalerer dette
ved at returnere null.</P>
<P CLASS="western">Driverne har p&aring; forh&aring;nd kaldt
DriverManager.registerDriver() og registreret sig selv.</P>
<PRE CLASS="ikke-javakode-western">import java.sql.*;
import java.util.*;

public class DriverManager
{
  private static Vector drivere = new Vector();

  public static Connection getConnection(String url) throws SQLException
  {
<SPAN LANG="da-DK">    <I>// G&aring; gennem alle de indl&aelig;ste drivere og fors&oslash;g at lave en forbindelse</I></SPAN>

<SPAN LANG="da-DK">    for (int i = 0; i &lt; drivere.size(); i++)</SPAN>
<SPAN LANG="da-DK">    {</SPAN>
<SPAN LANG="da-DK">      Driver d = (Driver) drivere.elementAt(i);</SPAN>

<SPAN LANG="da-DK">      Connection result = d.connect(url);</SPAN>
<SPAN LANG="da-DK">      if (result != null) {</SPAN>
<SPAN LANG="da-DK">        // Success!</SPAN>
<SPAN LANG="da-DK">        return result;</SPAN>
<SPAN LANG="da-DK">      }</SPAN>
<SPAN LANG="da-DK">    }</SPAN>

<SPAN LANG="da-DK"><I>    // kommer hertil var der ingen drivere der kunne klare forbindelsen</I></SPAN>
<SPAN LANG="da-DK">    throw new SQLException(&quot;No suitable driver&quot;);</SPAN>
<SPAN LANG="da-DK">  }</SPAN>

<SPAN LANG="da-DK"><I>/**</I></SPAN>
<SPAN LANG="da-DK"><I> * Drivere kalder denne metode n&aring;r de bliver indl&aelig;st, for at registrere sig selv</I></SPAN>
<SPAN LANG="da-DK"><I> */</I></SPAN>
<SPAN LANG="da-DK">  public static void registerDriver(Driver driver)</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    drivere.addElement(driver);</SPAN>
<SPAN LANG="da-DK">  }</SPAN>

<SPAN LANG="da-DK">  <I>// ... flere metoder</I></SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>

<P CLASS="western">Alle drivere skal implementere interfacet Driver.</P>
<PRE CLASS="ikke-javakode-western">import java.sql.*;

public interface Driver
{
<SPAN LANG="da-DK"><I>/**</I></SPAN>
<SPAN LANG="da-DK"><I> * N&aring;r DriverManager.getConnection() kaldes, kalder den denne metode i hver</I></SPAN>
<SPAN LANG="da-DK"><I> * af sine indl&aelig;ste drivere, for at finde en driver der passer.</I></SPAN>
<SPAN LANG="da-DK"><I> * @return Forbindelse til databasen, eller null hvis denne driver ikke passer</I></SPAN>
<SPAN LANG="da-DK"><I> * @param url Adressen p&aring; databasen, f.eks. &quot;jdbc:odbc:datakilde1&quot;</I></SPAN>
<SPAN LANG="da-DK"><I> * eller &quot;jdbc:oracle:thin:@ora.javabog.dk:1521:student&quot;</I></SPAN>
<SPAN LANG="da-DK"><I> */</I></SPAN>

<SPAN LANG="da-DK">  Connection connect(String url) throws SQLException;</SPAN>
<SPAN LANG="da-DK">  </SPAN>
<SPAN LANG="da-DK">  // ... flere metoder</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<P CLASS="western">Driver-klasserne skal ogs&aring; s&oslash;rge for,
n&aring;r de bliver indl&aelig;st, at registrere sig hos
DriverManager. Lad os forestille os, at vi vil skrive en driver til
databasen Xyz, som skal genkende URL'er p&aring; formen
&quot;jdbc:xyz:...&quot;. Hvis den f&aring;r en passende URL,
returnerer den et XyzConnection-objekt, ellers null.</P>
<PRE CLASS="ikke-javakode-western">import java.sql.*;

public class XyzDriver implements Driver
{
  <I>// Klasseinitialiseringsblok - k&oslash;res &eacute;n gang n&aring;r klassen indl&aelig;ses</I>
<SPAN LANG="da-DK"><B>  static</B></SPAN>
<SPAN LANG="da-DK"><B>  {</B></SPAN>
<SPAN LANG="da-DK"><B>    Driver drv = new XyzDriver();</B></SPAN>
<SPAN LANG="da-DK"><B>    DriverManager.registerDriver( drv );</B></SPAN>
<SPAN LANG="da-DK"><B>  }</B></SPAN>

<SPAN LANG="da-DK">  public Connection connect(String url) throws SQLException</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    <I>// passer URLen til min driver?</I></SPAN>
<SPAN LANG="da-DK">    if (url.startsWith(&quot;jdbc:xyz:&quot;))</SPAN>
<SPAN LANG="da-DK">    {</SPAN>
<SPAN LANG="da-DK">      <I>// kode til at oprette et passende Connection-objekt</I></SPAN>
<SPAN LANG="da-DK">      return new XyzConnection(url);</SPAN>
<SPAN LANG="da-DK">    }</SPAN>
<SPAN LANG="da-DK">    </SPAN>
<SPAN LANG="da-DK">    <I>// hvis URL'en ikke startede med &quot;jdbc:xyz:&quot; s&aring; returner null</I></SPAN>
<SPAN LANG="da-DK">    <I>// og s&aring; vil en anden driver blive fors&oslash;gt.</I></SPAN>
<SPAN LANG="da-DK">    return null;</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">  </SPAN>
<SPAN LANG="da-DK">  <I>// ... flere metoder</I></SPAN>
<SPAN LANG="da-DK">}</SPAN>
</PRE>

<H3 CLASS="western">17.6.2 <a name='afsn17.6.2'></a>Eksempel: Fortolkning af
matematikfunktioner</H3>
<P CLASS="western">Vi forestiller os, at et program til at tegne
kurver dynamisk skal kunne udvides med flere funktioner. Funktioner,
implementerer alle interfacet Funktion:</P>
<PRE CLASS="kode-western">public interface Funktion
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  public double beregn(double x);</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<P CLASS="western">Alle klasserne har en navngivning, der tillader
dem at blive dynamisk indl&aelig;st: De hedder alle Funktion_ og s&aring;
navnet, f.eks. repr&aelig;senterer klassen Funktion_sin funktionen
sinus:</P>
<PRE CLASS="kode-western">public class Funktion_sin implements Funktion
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  public double beregn(double x)</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    return Math.sin(x);</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<P CLASS="western">Funktions-fortolkeren indl&aelig;ser klasser, som
implementerer Funktion-interfacet ud fra funktionens navn dynamisk:</P>
<PRE CLASS="kode-western">public class FunktionsfortolkerDynBind
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  public Funktion findFunktion(String navn)</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    try </SPAN>
<SPAN LANG="da-DK">    {</SPAN>
<SPAN LANG="da-DK">      <I>// Pr&oslash;v at indl&aelig;se en klasse der hedder f.eks. Funktion_sin</I></SPAN>
<SPAN LANG="da-DK">      Class <B>klasse =   Class.forName(&quot;Funktion_&quot;+navn);</B></SPAN>

<SPAN LANG="da-DK"><I>      // Opret et objekt fra klassen</I></SPAN>
<SPAN LANG="da-DK">      Funktion f = (Funktion) <B>klasse.newInstance()</B>;</SPAN>

<SPAN LANG="da-DK">      return f;</SPAN>
<SPAN LANG="da-DK">    }</SPAN>
<SPAN LANG="da-DK">    catch (Exception ex)</SPAN>
<SPAN LANG="da-DK">    {</SPAN>
<SPAN LANG="da-DK">      ex.printStackTrace();</SPAN>
<SPAN LANG="da-DK">      throw new IllegalArgumentException(&quot;ukendt funktion: &quot;+navn);</SPAN>
<SPAN LANG="da-DK">    }</SPAN>
<SPAN LANG="da-DK">  }</SPAN>

<SPAN LANG="da-DK">  public Funktion fortolk(String udtryk)</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    <I>// endnu ikke implementeret - returner bare noget.</I></SPAN>
<SPAN LANG="da-DK">    return findFunktion(&quot;sin&quot;);</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE><P CLASS="western">
Klientprogrammer kalder analyser() med en streng og f&aring;r en
tilsvarende Funktion ud. Programmet kan senere udvides med f.eks.
Funktion_cos, Funktion_tan o.s.v<A CLASS="sdfootnoteanc" NAME="sdfootnote1anc" HREF="#sdfootnote1sym"><SUP>1</SUP></A>.</P>


<P CLASS="western">Her er et eksempel p&aring; brug:</P>
<PRE CLASS="kode-western">public class BenytFunktionsfortolkerDynBind
<SPAN LANG="da-DK">{</SPAN>
<SPAN LANG="da-DK">  public static void main(String arg[])</SPAN>
<SPAN LANG="da-DK">  {</SPAN>
<SPAN LANG="da-DK">    FunktionsfortolkerDynBind analysator = new FunktionsfortolkerDynBind();</SPAN>
<SPAN LANG="da-DK">    Funktion f = analysator.fortolk(&quot;sin(5*cos(x))&quot;);</SPAN>
<SPAN LANG="da-DK">    System.out.println(&quot;f(1)=&quot; + f.beregn(1) );</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE>
<H2 CLASS="western">17.7 <a name='afsn17.7'></a>Opgaver</SPAN></H2>
<H4 CLASS="western">Proxy</H4>
<P CLASS="western"><SPAN STYLE="font-weight: medium">L&aelig;s <a href='kapitel16.jsp#afsn16.8.3'>afsnit
16.8.3</a>, Dataforbindelse, der cacher foresp&oslash;rgsler, og lav med,
udgangspunkt i eksemplet, proxy-klassen Dataforbindelseslogger, der
skriver ud til sk&aelig;rmen hver gang der kaldes en metode p&aring;
dataforbindelsen.</SPAN></P>
<H4 CLASS="western">Dynamisk Binding</H4>
<OL>
  <LI><P CLASS="western">Metoden findFunktion() i
  FunktionsfortolkerDynBind kan g&oslash;res mere effektiv ved at
  huske de allerede indl&aelig;ste Funktion-klasser, s&aring;dan at en
  funktion kun bliver indl&aelig;st &eacute;n gang. <BR>Udvid
  fortolkeren med en afbildning (en HashMap), der afbilder allerede
  indl&aelig;ste funktionsnavne (strenge) over i de tilsvarende
  klasser.</P>
  <LI><P CLASS="western">Udvid Funktionsfortolker fra <a href='kapitel4.jsp#afsn4.7.2'>afsnit 4.7.2</a> til
  at bruge dynamisk binding.</P>
</OL>

<H4 CLASS="western">Designm&oslash;nstre i JDBC</H4>
<P CLASS="western"><SPAN LANG="da-DK">Kig i <a href='kapitel8.jsp#afsn8.1'>afsnit 8.1</a>, Basisfunktioner i JDBC.
Hvilke designm&oslash;nstre kan du se, der er anvendt i
JDBC-biblioteket, ud fra beskrivelsen?</SPAN></P>
<OL>
  <LI><P CLASS="western">N&aelig;vn 2 fabrikeringsmetoder.</P>
  <LI><P CLASS="western">N&aelig;vn mindst 2 andre designm&oslash;nstre
  anvendt i JDBC, og beskriv dem.</P>
</OL>
<P CLASS="western">Svarene findes i n&aelig;ste afsnit.</P>

<H2 CLASS="western" STYLE="">17.8 <a name='afsn17.8'></a>L&oslash;sninger</SPAN></H2>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel17.jsp#afsn17.8">
  <input type='checkbox' name='vis' value='17.8'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='17.8'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western" STYLE="font-weight: medium">17.8.1 <a name='afsn17.8.1'></a>Dataforbindelseslogger</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel17.jsp#afsn17.8.1">
  <input type='checkbox' name='vis' value='17.8.1'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='17.8.1'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">
17.8.2 <a name='afsn17.8.2'></a>Designm&oslash;nstre i JDBC</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel17.jsp#afsn17.8.2">
  <input type='checkbox' name='vis' value='17.8.2'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='17.8.2'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  
<DIV ID="sdfootnote1">
  <P CLASS="sdfootnote-western"><A CLASS="sdfootnotesym" NAME="sdfootnote1sym" HREF="#sdfootnote1anc">1</A>Dette
  eksempel kan dog ikke tage h&oslash;jde for sammensatte funktioner
  som f.eks. sin(5*x+1), da Funktion-objekter ikke kan kombineres. Se
  <a href='kapitel4.jsp#afsn4.7.2'>afsnit 4.7.2</a> for et eksempel, der tager h&oslash;jde for sammensatte
  funktioner.</P>
</DIV>

<a href='http://javabog.dk/'>javabog.dk</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel16.jsp'>&lt;&lt; forrige</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='indhold.jsp'>indhold</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel18.jsp'>n&aelig;ste &gt;&gt;</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kode/'>programeksempler</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='../index_VP.html'>om bogen</a>
<hr>
<font size=-2>http://javabog.dk/ - <b></b> af Jacob Nordfalk.
<br>
  Licens og kopiering under <a href='http://www.linuxbog.dk/licens.html'>&Aring;ben Dokumentlicens</a> (&Aring;DL)
  hvor intet andet er nævnt (71% af værket).
</font>
<br>
Ønsker du at se de sidste 29% af dette værk (362838 tegn)
skal du købe bogen. Så får du pæne figurer og layout, stikordsregister og en trykt bog med i købet.
<!-- netlæser: Wget/1.10, autoHent: true  -->
     

</body>
</html>
