© 1999-2003, Flemming Koch Jensen
Alle rettigheder forbeholdt
Adapter Pattern
Vejledende løsninger

 

 

1 Adapter kan implementeres på følgende måde:
class Adapter {
  
  private Adaptee file;
  private String filename;

Datakernen indeholder to instansvariable. Det følger af Adapter Pattern at Adapter'en skal have en reference til Adaptee, som vi kalder file, da Adaptee repræsenterer en file. Den anden instansvariavel - filename - er nødvendig for at kunne implementere filename-metoden (se senere).

  public Adapter( Adaptee f ) {
    file = f;
  }

Konstruktoren bruges til at oprette forbindelsen fra Adapter til Adaptee.

  public boolean open( String fn, boolean write, boolean append ) {
    /*
     *   Åbner en file - append angiver boolsk om der skal appendes til filen
     *                 - write angiver boolsk om filen skal åbnes for skrivning
     *                   eller læsning
     *   (det kan ikke antages at filen er lukket efter et read)
     */
    close();

    filename = fn;
    file.setFilename( filename );
  
    if ( !write )
      return file.openRead();
    else if ( append )
      return file.openWriteAppend();
    else
      return file.openWriteNew();
  }
Før vi åbner filen lukker vi først en evt. tidligere file, da vi ikke kan være sikre på at en sådan er lukket før kaldet af open-metoden. Vi gemmer filenavnet til filename-metoden (se senere), og kalder setFilename-metoden på Adaptee før vi begynder at åbne filen.

Target adskiller sig fra Adaptee ved, at den kun har en open-metode, mens Adaptee har hele tre. Ud fra parametrene vælges mellem de tre open-metoder i Adaptee.

  public boolean close() {
    /*
     *   Lukker filen
     */
    return file.close();
  }

close-metoden er "ren" Handle Pattern.

 
Hernæst følger diverse print-metoder. Generelt er de implementeret så de anvender hinanden, for at undgå for megen kode-redundans, og der er anvendt mellemrum for at opbygge linier med den ønskede felt-bredde.
Det fremgår ikke af opgaven hvad der skal ske når en linie er breddere end det felt den skal placeres i. Vi vælger at lade for store linier bredde sig.
  public boolean printLeft( Object obj, int bredde ) {
    /*
     *   udskriver en tekst repræsentation af objektet venstrestillet
     *   i et felt på 'bredde' tegn (uden linieskift)
     */
    String s = obj.toString();
    
    while ( s.length() < bredde )
      s += " ";
      
    return print( s );
  }

Vi venstrestiller i feltet ved at fylde mellemrum efter linien, indtil den har den ønskede bredde. Dernæst kaldes print-metoden, der udskriver vha. Adaptee.

  public boolean printlnLeft( Object obj, int bredde ) {
    /*
     *   udskriver en tekst repræsentation af objektet venstrestillet
     *   i et felt på 'bredde' tegn (med linieskift)
     */
    if ( !printLeft( obj.toString(), bredde ) )
      return false;
    return print( "\r\n" );
  }

printlnLeft kalder printLeft og supplerer med et linieskift. Bemærk at linieskiftet er platformsafhængigt (Windows).

 
printRight-metoderne er analoge til printLeft-metoderne:
  public boolean printRight( Object obj, int bredde ) {
    /*
     *   udskriver en tekst repræsentation af objektet højrestillet
     *   i et felt på 'bredde' tegn (uden linieskift)
     */
    String s = obj.toString();
    
    while ( s.length() < bredde )
      s = " " + s;
      
    return print( s );
  }
  
  public boolean printlnRight( Object obj, int bredde ) {
    /*
     *   udskriver en tekst repræsentation af objektet højrestillet
     *   i et felt på 'bredde' tegn (med linieskift)
     */
    if ( !printRight( obj.toString(), bredde ) )
      return false;
    return print( "\r\n" );
  }

Dernæst følger print-metoden, som er blevet anvendt flittigt i det foregående:

  public boolean print( Object obj ) {
    /*
     *   udskriver en tekst repræsentation af objektet (uden linieskift)
     */
    String s = obj.toString();
    
    for ( int i=0; i<s.length(); i++ )
      if ( !file.print( s.charAt( i ) ) )
        return false;
    
    return true;
  }

Den implementeres ved at kalde Adaptee med ét tegn af gangen, indtil hele tekststrengen er udskrevet.

  public boolean println( Object obj ) {
    /*
     *   udskriver en tekst repræsentation af objektet (med linieskift)
     */
    return print( obj.toString() + "\r\n" );
  }

println-metoden anvender også print-metoden.

  public String filename() {
    /*
     *   returnerer filenavnet
     */
    return filename;
  }

filename-metoden er afhængig af, at vi har gemt filenavnet, da Adaptee ikke husker på filens navn, og derfor ikke kan hjælpe os. filename-metoden er derfor ikke nogen "rigtig" Adapter-metode.

  public String readLine() {
    /*
     *   læser en linie fra filen
     */
    String s="";
    
    char c = file.read();
    while ( c != (char) -1 && c != '\r' ) { // så længe ikke slut eller linieskift
      s += c;
      c = file.read();
    }
    
    if ( file.read() == (char) -1 && s.length() == 0 ) // slipper også af med \n
      return null;
    
    return s;
  }

Adaptee tilbyder kun, at man kan indlæse ét tegn af gangen, og readLine-metoden må derfor lave langt det meste af arbejdet selv.

  public boolean dump() {
    /*
     *   udskriver filen på skærmen (kan ikke regne med at filen er hverken lukket
     *   efter write eller er åbnet til indlæsning)
     */
    String s;
    
    close();
    if ( !open( filename, false, false ) )
      return false;
    
    s = readLine();
    while ( s != null ) {
      System.out.println( s );
      s = readLine();
    }
    
    return true;
  }
}

Der findes ikke noget lignende dump-metoden i Adaptee. Vi laver den derfor - mere eller mindre - fra bunden.

 
Endelig har vi test-anvendelsen:
class TestAdapter {
  
  public static void main( String argv[] ) {
    
    Adapter file = new Adapter( new Adaptee() );
    
    file.open( "Test.txt", true, false );
    
    file.println( "Dette er en test" );
    file.printlnRight( new Integer( 1842784392 ), 20 );
    file.printLeft( "Title:", 10 );
    file.println( "Client having 'tee' with Adapter" );
    
    file.dump();
  }
}

Dette er en test
          1842784392
Title:    Client having 'tee' with Adapter

Kildetekster:

Adapter.java
TestAdapter.java