Chapter 8
Design af klassehierarkier

Kurt Nørmark ©
Department of Computer Science, Aalborg University, Denmark


September 2001


Abstract
Previous lecture Next lecture
Index References Contents
I denne lektion vil vi studere mekanismer i det objekt-orienterede paradigme, som retter sig mod design af klassehierarkier. Som sædvanlig ser vi både på emnet generelt og specifikt i forhold til Java. Abstrakte klasser og ikke mindst klassehierarkier med abstrakte klasser er et meget relevant emne i forhold til denne lektion. Java's interface begreb vil også blive gennemgået. Endvidere vil vi kort tangere mulighederne og problemerne med multipel nedarvning, samt sætte dette i forhold til Java's brug af interfaces


Abstrakte klasser

Abstrakte klasser
Slide Note Contents Index
References 
Abstrakte klasser anvendes når vi skal designe de mest generelle dele af et klassehierarki. Der skal defineres subklasser af abstrakte klasser for at nyttiggøre disse. Vi vil her introducere de generelle begreber og ideer. På de efterfølgende sider vil vi se på Java detaljerne.

Abstrakte klasser anvendes til at repræsentere generelle begreber, som ikke kan eller ønskes implementeret på dette niveau

The concept abstrakt klasse: En abstrakt klasse er en klasse med abstrakte metoderEn abstrakt klasse er en klasse, som foruden 'normale metoder' også indeholder én eller flere forudannoncerede metoder, uden krop
The concept abstrakt metode: En abstrakt metode er en særligt markeret metode uden kropEn forudannonceret metode er markeret med modifieren 'abstract'
The concept forudannoncering: En abstrakt metode siges også at være forudannonceret
The concept konkret klasse: En ikke-abstrakt klasse kaldes undertiden for en konkret klasseKlasser som ikke er abtrakte vil undertiden blive kaldt konkrete klasser. Ligeledes bruges denne terminlogi for metoder

  • Det er ikke muligt at lave instanser af en abstrakt klasse

  • Abstrakte metoder skal defineres fuldt ud i en subklasse af den abstrakte klasse

Da abstrakte klasser mangler detaljer i kroppen af abstrakte metoder giver det ikke mening at instantiere klasserne. Hvis vi gjorde det, kunne vi ikke opererere på dem.

Eksempelvis kan klassen Konto defineres som en abstrakt klasse, hvis vi kun ønsker at arbejde med instanser af mere specialiserede kontotyper

Reference

Eksempel: Stack
Slide Note Contents Index
References 
Det første eksempel vi ser på er den velkendte Stack udsat for abstrakte klasser

I den abstrakte klasse Stack har vi endnu ikke lagt os fast på en datarepræsentation

Program: Den abstrakte klasse Stack. Klassen indeholder en række abstrakte metoder samt to konkrete metoder, hvoraf den mest bemærkelsesværdige er toggleTop. Metoden toggleTop ombytter de to øverste elementer på stakken, forudsat naturligvis at stakken har mindst to elementer. Ved brug af push, pop og top operationerne kan vi implementere toggleTop på det abstrakte niveau. Metoden toggleTop arves naturligvis af alle konkrete subklasser af den abstrakte Stack.
abstract class Stack{ 
  
  abstract public void push(Object el);
  abstract public void pop();
  abstract public Object top();
  abstract public boolean full();
  abstract public boolean empty();
  abstract public int size();

  public void toggleTop(){
    if (size() >= 2){
      Object topEl1 = top();  pop();
      Object topEl2 = top();  pop();
      push(topEl1); push(topEl2);
    }
  } // toggleTop

  public String toString(){
    return("Stack");
  }
} // end Stack

Abstrakte klasser: Skematisk eksempel
Slide Note Contents Index
References 
Efter at have set på et konkret eksempel på en abstrakt klasse vil vi her skitsere et hierarki af abstrakte og konkrete klasser.

Figure. En grafisk skitse af et klassehierarki, hvor C arver fra B som arver fra A. Kursive navne henviser til abstrakte klasser og metoder. På figuren er de røde metoder abstrakte, og de blå er ikke-abstrakte. A og B er abstrakte klasser. Dog er B 'lidt mere konkret' end A, idet operationen Q i B er defineret fuldt ud. B er abstrakt idet B ikke har defineret den abstrakte metode P, som arves fra A. C er en konkret klasse, hvori både P og Q er fuldt ud definerede operationer. Endvidere er der kommet en ny operation S til.

Abstrakte klasser i Java
Slide Note Contents Index
References 
Vi vil nu introducere abstrakte klasser i forhold til Java

Syntax: Syntaksen for definition af en abstrakt klasse. På dette niveau er er den eneste syntaktiske forskel, at 'modifieren' abtract er benyttet.

abstract class klasseNavn {    
  dataErklæringer
  konstruktorer
  metoder
}

  • Klasser som indeholder en abstrakt metode skal erklæres abstrakt

  • Det er tilladt at erklære abstrakte klasser uden abstrakte metoder

  • Det er muligt - men atypisk - at aflede en abstrakt klasse fra en konkret klasse

  • Konstruktorer giver mening i abstrakte klasse, også selv om en abstrakt klasse ikke kan instantieres

Abstrakte klasser, som ikke har abstrakte metoder, kan naturligvis (heller) ikke instantieres

Når vi siger, at en abstrakt klasse i Java kan afledes fra en konkret klasse mener vi at en subklasse kan være abstrakt selv om den's superklasse er konkret. Dette kan måske bruges til i et stort klassehierarki at introducere niveauer mellem konkrete klassser, som vi vil forhindre instantiering af

Abstrakte metoder i Java
Slide Note Contents Index
References 
I forlængelse af ovenstående introducerer vi her abstrakte metoder i forhold til Java

En abstrakt metode angives som en signatur

Nøgleordet 'abstract' pointerer, at metoden er abstrakt

Syntax: Syntaksen for definition af en abstrakt metode. Bemærk, at vi kun angiver metodehovedet. Der er altså ingen krop i { ... } i en abstrakt metode

abstract synlighed returType metodeNavn (parametre)

Eksempel: Stakken igen
Slide Note Contents Index
References 
Vi vender her tilbage til stak eksemplet. Vores primære ærinde er at se på en konkret specialisering af den abstrakte klase Stack.

Program: Den abstrakte klasse Stack igen.
/user/normark/courses/prog1/prog1-01/sources/java/noteEksempler/klasse-design/AbstractClassEx.java

Program: En konkret specialisering af Stack uden øvre begrænsning, baseret på klassen Vector. De grønne dele er nytilføjede data i klassen. Den abstrakte klasse havde ingen data erklæringer overhovedet. Den brune del implementerer konstruktorern for UnboundedStack. De blå dele implementerer de abstrakte metoder. Den lilla del redefinerer toString metoden.
class UnboundedStack extends Stack{

  private int topIndex;
  private Vector store;

  public UnboundedStack(){
    store = new Vector(100);
    topIndex = 0;
  }

  public void push(Object el){
    if (topIndex > store.capacity() - 5)
       store.ensureCapacity(store.capacity() + 100);
    if (! full()){  
      store.add(topIndex, el);
      topIndex = topIndex + 1;
    }
  }
     
  public void pop(){
    if (! empty()){
      topIndex = topIndex - 1;
    }
  }

  public Object top(){
    if (!empty()){
      return (store.elementAt(topIndex - 1));
    } 
    else return (null);
  }
 
  public boolean full(){
    return false;
  }

  public boolean empty(){
    return(topIndex <=  0);
  }
    
  public int size(){
    return (topIndex);
  }

  private String stackContents(){
    StringBuffer st = new StringBuffer();
    for (int i = topIndex - 1 ; i >= 0; i--){
      st.append(store.elementAt(i).toString());
      st.append(".");
    }
      
    return (st.toString());
  }

  public String toString(){
    return(super.toString() + ": " +  stackContents());
  }
} // end UnboundedStack

Program: Et eksempel på en anvendelse af klassen UnboundedStack. Programmet udskriver 'Stack: 3.1.' svarende til at toppen af stakken er 3, og 'bunden' er 1.
public class AbstractClassEx {

 public static void main(String[] args){
   UnboundedStack st = new UnboundedStack();
  
   st.push(new Integer(1));
   st.push(new Integer(2));
   st.push(new Integer(3));
   st.toggleTop();
   st.pop();
   
   System.out.println(st);
  }
} // end AbstractClassEx

Eksempel: Comparable
Slide Note Contents Index
References 

Program: Den abstrakte klasse Comparable. Givet at subklasser af Comparable definerer lessThan, som er abstrakt i Comparable, bidrager klassen med konkrete metoder for lessThanOrEqual, greaterThan og greaterThanOrEqual. Denne blanding af abstrakte og konkrete metoder udgør en stærk mulighed, når vi arbejder med abstrakte klasser.
abstract class Comparable {
  
  /** Return whether I am less than other? */
  abstract boolean lessThan(Comparable other);

  /** Return whether I am less than or equal to other? */
  boolean lessThanOrEqual (Comparable other){
    return (this.lessThan(other) || this.equals(other));
  }

  /** Return whether I am greater than other? */
  boolean greaterThan (Comparable other){
    return (!this.lessThanOrEqual(other));
  }

  /** Return whether I am greater than or equal to other? */
  boolean greaterThanOrEqual(Comparable other){
    return (!this.lessThan(other));
  }
}

Det giver kun mening at sammenligne objekter som tilhører samme klasse

Dette er svært at udtrykke statisk i Java

I ovenstående klasse giver det kun mening at sammenligne to objekter af samme klasse. Dette sikres ikke i den viste klasse. Statisk set er der intet til hinder for at sammenligne et bankkonto objekt med en cirkulær liste, forudsat at begge er Comparable. Dette er utilfredsstillende, og det giver ikke mening. Det ville have været værdifuldt at kunne udtrykke, at typen af parameteren (af f.eks. lessThan) skal være af samme type som det objekt, hvorpå lessThan aktiveres. Eiffel, som er stærk inden for multipel nedarvning, tilbyder en sådan mulighed (idet typen af en parameter kan angives som 'like Current')

Exercise 8.1. Sammenlignelige bankkontiI forelæsningen studerede vi en abstrakt klasse Comparable, der definerer en ordning på objekter som er instanser af (subklasser af) Comparable. (Det er kun intentionen at kunne sammenligne objekter i samme klasse. Som bemærket i forelæsningsnoterne er dette svært at sikre statisk i Java).

Definer nu et Java Interface Comparable, som svarer til den abstrakte klasse Comparable. Interfacet Comparable skal altså have fire operationer: lessThan, lessThanOrEqual, greaterThan og greaterThanOrEqual.

Afprøv interfacet Comparable ved at definere en specialisering af klassen Konto, som implementerer interfacet Comparable. Specialiseringen skal hedde CompKonto. Vi antager at en konto k1 er mindre end k2 hvis saldoen af k1 er mindre end saldoen af k2. Specielt er kontoen k1 er lig med k2 (k1.equals(k2)) hvis de indeholder det samme beløb. Redefiner i den forbindelse equals i den nye Konto klasse.

Afprøv den specialiserede Konto klasse i et simpelt hovedprogram, som laver to Konto objekter og sammenligner disse med hinanden. Da mange sikkert ikke har tid til at lave et hovedprogram selv, kan I vælge at benytte mit hovedprogram. Dermed består opgaven altså I at lave interfacet og en Konto specialisering, som implementerer interfacet.

Eksempel: Microbib
Slide Note Contents Index
References 
Vi vil her diskutere dele af et eksempelprogram, som organiserer litteratur i et klassehierarki.

Figure. Hierarkiet af litteratur i microbib eksemplet, illustreret med OOD notation ala UML. Klasserne Book, Journal (dk: tidsskrift) og Article arver fra en abstrakte klasse Literature. en Article er endvidere en del af en Journal. Et LiteratureCollection objekt er en container, som består af Literature

  • Design aspekter

    • Literature indeholder en abstrakt printItem operation, som kaldes af en ikke abstrakt print operation

    • Literature indeholder en match operation, som redefineres og kombineres i Literature hierarkiet

Program: Den abstrakte klasse Literature. Vi har fremhævet de aspekter som har med metoderne printitem og match at gøre.
/user/normark/courses/prog1/prog1-01/sources/java/microbib/Literature.java

Program: Den konkrete subklasse Book af Literature.
/user/normark/courses/prog1/prog1-01/sources/java/microbib/Book.java

Program: Klassen LiteratureCollection. I denne klasse fokuserer vi på anvendelsen af print og match fra Literature klassehierarkiet.
/user/normark/courses/prog1/prog1-01/sources/java/microbib/LiteratureCollection.java


Multipel nedarvning

Hvorfor multipel nedarvning?
Slide Note Contents Index
References 
Vi vil indledningsvis overveje, hvorfor man kunne ønske sig at arve fra to eller flere klasser i et objekt-orienteret program

  • Hvorfor mulitipel nedarvning?

    • Samling af multiple specialiseringer

      • Eksempel: Ligebenet retvinklet trekant

      • Eksempel: Konto som både er checkkonto og gevinstkonto

    • Programtransport fra flere kilder

      • En måde at formidle egenskaber til en klasse fra et antal klasser.

      • Eksempel: FixedStack

References

Problemstillinger ved multipel nedarvning
Slide Note Contents Index
References 
Vi så kort i forrige lektion at en klasse kan arve fra mere end én klasse i nogle objekt-orienterede programmeringssprog. Vi vil nu se lidt nærmere på dette, og vi vil identificere nogle af de problemer og udfordringer, der opstår i den sammenhæng.

Figure. En situation hvor navnet x arves af C fra både A og B

  • Problemstillinger:

    • Navnesammenfaldsproblemet: Hvilken egenskab refererer x til i C?

    • Kombinationsproblemet: Kan x fra A og B kombineres i C?

    • Selektionsproblemet: Kan man fra C vælge mellem x fra A eller B?

    • Replikationsproblemet: Ønsker vi to x-er i C?

Lad os først understrege at de fire problemstillinger hænger ganske tæt sammen. Når vi taler om navnesammenfald som et problem er det ud fra en filosofi om, at et navn kun kan referere til én egenskab (én routine og/eller én instansvariabel). Hvis flere egenskaber har samme navn er det tvetydigt, hvilken egenskab vi egentlig mener.

Som et alternativ til at løse navnesammenfaldsproblemet kan man forsøge at løse kombinationsproblemet. Filosofien er nu at vi refererer til begge (alle) egenskaber i en eller anden kombination. Kunststykket er naturligvis så at finde ud af, hvordan man generelt, eller for bestemte slags egenskaber, kan danne kombinationer.

Multipel klassificering
Slide Note Contents Index
References 
Der findes ikke en entydig klassificering af objekters egenskaber. Herunder viser vi et eksempel på flere forskellige klassificeringer af objekter. Da disse overlapper bliver der behov for at lave klasse (og objekter) som er placeret i det overlappende felt. Dette leder umiddelbart til et behov for multipel nedarvning

Figure. Klasserne C1 og C2 illustrerer behovet for at kunne arve fra to eller flere klasser, som på overlappende vis klassificerer den totale mængde af objekter i et objekt-orienteret system. Flere af ovenstående klasseficeringer findes i Java, dog ikke som klasser, men som Interfaces

Multipel og overlappende klassificering giver et naturligt behov for at klasser såsom C1 og C2 arver fra to eller flere af de overordnede klassificeringer

Multipel nedarvning: Fornuftsægteskab
Slide Note Contents Index
References 
Vi ser her på en form for multipel nedarvning, hvor vi dels arver fra en abstrakt klasse, dels fra en meget konkret klasse.

Figure. En situation hvor FixedStack arver fra hhv. Stack og Array

Program: Skitse af FixedStack som kan friste til multiple nedarvning (kan ikke oversættes). De med blåt fremhævede steder i programmet viser de steder, hvor der anvendes egenskaber fra Array (som vi her forestiller os, at vi har arvet fra). Som bekendt findes denne klasse ikke direkte i Java klassebiblioteket.
class FixedStack extends Stack,
                 extends Array {
  private int topIndex;

  public FixedStack(){
    // initialize Array aspect somehow
    topIndex = 0;
  }

  public boolean full(){
    return(topIndex >=  maxSize());
  }

  public boolean empty(){
    return(topIndex <=  0);
  }
    
  public void push(Object el){
    if (! full()){  
      put(topIndex, el);
      topIndex = topIndex + 1;
    }
  }
     
  public void pop(){
    if (! empty()){
      topIndex = topIndex - 1;
    }
  }

  public Object top(){
    if (!empty()){
      return (at(topIndex - 1));
    } 
    else return (null);
  }
 
  private String stackContents(){
    StringBuffer st = new StringBuffer();
    for (int i = 0; i < topIndex; i++){
      st.append(at(i).toString());
      st.append(".");
    }
      
    return (st.toString());
  }

  public String toString(){
    return("Stack: " + stackContents());
  }
} // end FixedStack

  • FixedStack er en konkret klasse

    • Arver den noble funktionalitet fra Stack

    • Arver den substantielle funktionalitet fra Array.


Interfaces

Interface begrebet
Slide Note Contents Index
References 
Vi starter vores behandling af interfaces med et overordnet 'kig' på interface begrebets egenskaber

Et interface udtrykker en hensigtserklæring om en bestemt samling af funktionalitet uden nogen form for implementering af denne

The concept interface: Et interface er en klasse-lignende samling af erklæringer uden egentlig 'substans'

Et interface indeholder ikke variable eller metoder med kroppe

Et interface (ala Java) er en samling af metode specifikationer og konstant definitioner. Med en metode specifikation mener vi en metode uden krop, også kaldet en metode signatur

  • Overordnet om definition og anvendelse af interfaces

    • Kan beskrive signaturerne af en mængde metoder, som man kan påtvinge en klasse at implementere

    • Kan også anvendes til definition af en række konstanter, som kan arves af vilkårlige klasser

    • Kan bruges som typer

      • Man kan erklære variable og parametre af 'interface typer'

    • Kan relativt problemfrit organiseres i multiple nedarvningshierarkier

Hvis man i en klasse C implementerer to interfaces, som indeholder samme konstant, vil der være en konflikt. Denne konflikt forhindrer at C kan oversættes. Andre konflikter eksisterer ikke

Interface i Java: Syntaktiske regler
Slide Note Contents Index
References 
Vi ser her på de syntaktiske regler for definition af Interfaces (med og uden super interfaces), samt for hvorledes en klasse kan angive, at den implementerer et interface

Syntax: Et interface er en navngivning mængde af konstant og metode-signatur erklæringer

interface interfaceNavn {
  konstant og metodesignatur erklæringer
}

En klasse kan påtvinges at skulle implementere én eller flere interfaces, og samtidig arve fra én superklasse:

Syntax: En klasse, som arver fra en superklasse, kan endvidere implementere en eller flere interfaces, her interfaceNavn1 og interfaceNavn2 (og evt. flere på de tre prikkers plads)

class subKlasse extends superKlasse implements interfaceNavn1,
                                               interfaceNavn2,
                                               ... {    
 erklæringer
}

Et interface kan udvide én eller flere andre interfaces:

Syntax: Et interface kan udvide én eller flere interfaces

interface interfaceNavn extends interfaceNavn1, 
                                interfaceNavn2,
                                ... {    
  konstant og metodesignatur erklæringer
}

Interfaces i Java: Semantiske regler
Slide Note Contents Index
References 
I kølvandet på de syntaktiske regler nævnt ovenfor observerer vi her en række mere semantiske regler omkring brugen af interfaces i Java

  • Type:

    • Et interface kan anvendes som type, præcist som en klasse

    • En variabel eller parameter, der er type-erklæret med et interface, er polymorf

      • Ethvert objekt af en klasse, som implementerer interfacet, kan refereres af variablen eller parameteren

  • Instantiering:

    • Det giver ikke mening at instantiere et interface

  • Synlighed:

    • Et interface kan være offentlig (public) eller synlig i sin pakke (default)

    • Alle metoder i et interface er implicit public abstract

      • Man kan ikke erklære en metode i et interface 'static', 'final', 'private' eller 'protected'

      • Stilistisk anbefaling: Undgå at bruge modifiers på metoder i en interface definition

    • Alle konstanter i et interface er implict public static final

      • Man kan ikke erklære en variabel for 'private' eller 'protected'

      • Man kan undlade at bruge modifiers 'public', 'static' og 'final' ved erklæring af konstanter i interfaces

Eksempel: StringInput og StringOutput
Slide Note Contents Index
References 
Ideen med disse interfaces er primært at givet eksempler på erklæring af rimelig realistiske interfaces i Java.

Interfacet StringInput specificerer en metode fromStringRepresentation, som initialiserer et eksiterende objekt fra en tekststreng

Interfacet StringOutput specificerer en metode toStringRepresentation, som producerer en strengrepræsentation af et objekt

Ideen er, at resultatet af toStringRepresentation skal kunne bruges af fromStringRepresentation

Program: Interfacet StringInput.
interface StringInput {
  /** Re-initializes the current object from the string s */
  void fromStringRepresentation(String s);
}

Program: Interfacet StringOutput. Bemærk at metoden toStringRepresentation svarer helt til metoden toString() i klassen Objekt.
interface StringOutput {
  /** Return a string representation of the current object */
  String toStringRepresentation ();
}

Program: Interfacet StringInputOutput som udvider både StringInput og StringOutput
interface StringInputOutput extends StringInput, StringOutput {
}

Eksempel: StringInput og StringOutput
Slide Note Contents Index
References 
Vi viser her hvordan StringInput og StringOutput interfacene kan anvendes. Lad os understrege, at eksemplet udelukkende er tænkt illustrativt i forhold til en demonstration af interfaces; eksemplet er ikke godt nok gennemført til at være praktisk brugbar (og der er næppe i Java behov for de metoder, som Interfacet specificerer)

Program: En klasse IoKonto som implementerer interfacet StringInputOutput. Metoderne i interfacet skal defineres i klassen IoKonto. Vi har vist et simpelt eksempel på, hvordan det kan gøres.
class IoKonto extends Konto implements StringInputOutput{

  private void init(double saldo, String navn){
    this.saldo = saldo; this.navn = navn;
  }

  public IoKonto(String navn){
    super(navn);
  }
 
  public String toStringRepresentation(){
    return("Konto[" + navn + "|" + saldo + "]");
  }

  public void fromStringRepresentation(String s){
    // only for demo purposes - too simple for realistic usage
   String nameComponent = s.substring(s.indexOf('[')+1, s.indexOf('|'));
   String saldoComponent = s.substring(s.indexOf('|')+1, s.indexOf(']'));
   init(Double.valueOf(saldoComponent).doubleValue(),nameComponent);
  }
} // end IoKonto

Program: Et eksempel på en klasse som anvender IoKonto.
class Bank5 {
 
   public static void main( String[] args ) {

     IoKonto k1 = new IoKonto("Børge"),
             k2 = new IoKonto("Karl");

     k1.indsæt(100.0);
     System.out.print("k1: ");
     System.out.println(k1.toStringRepresentation());

     k2.hæv(400.0);
     System.out.print("k2: ");
     System.out.println(k2.toStringRepresentation());

     System.out.print("k1 taken from k2's string representation: ");
     k1.fromStringRepresentation(k2.toStringRepresentation());
     System.out.println(k1.toStringRepresentation());

   }
} // end Bank5

Reference

Interfaces i Java Core API: Enumeration
Slide Note Contents Index
References 
Interfaces anvendes i udstrakt grad i Java bibliotekterne. Vi ser her nærmere på et antal eksempler, første Enumeration

Enumeration er et interface i pakken java.util som repræsenterer den basale iterator funktionalitet på containere

Program: Interfacet Enumeration som det er defineret i Java biblioteket i pakken java.util, og strippet for en stor mængde af javadoc kommentarer
package java.util;
public interface Enumeration {
    boolean hasMoreElements();
    Object nextElement();
}

References

Exercise 8.2. Iterator i cirkulær listeDenne opgave bygger endnu engang videre på opgaven om cirkulære lister, som vi har set på nogle gange under øvelserne i dette kursus. Det er naturligvis muligt at tage udgangspunkt i løsningen på denne opgave, enten jeres egen eller min løsning.

Udvid klassen CircularList med en operation elements, der returnerer en iterator for en cirkulær liste. Iteratoren skal være et objekt, der implementerer interfacet Enumeration. Det er tilladt at antage, at der ikke indsættes elementer i listen under et gennemløb.

Afprøv jeres nye CircularList klasse ved at gennemløbe en liste med brug af iteratoren.

Interfaces i Java Core API: Cloneable
Slide Note Contents Index
References 

En klasse C som implementerer interfacet Cloneable signalerer, at cloning af C-objekter er tilladt

Interfacet Cloneable er tomt

  • Hvordan man en laver en klasse, hvis instanser kan klones

    • Lav en passende subklasse C som implementerer Cloneable

    • Definer en clone metode i C, som blot kalder den protectede super.clone() i Object

    • Clone metoden skal - via undetagelseshåndtering - håndtere tilfældet hvor cloning ikke er understøttet

    • Erklær clone metoden i C for public

Det forårsager en undtagelse (exception) hvis man sender besked clone til et objekt, hvis klasse ikke implementerer interfacet Cloneable (hvis klassen ikke har signaleret, at det er OK at clone).

Program: Klassen Point defineret som cloneable. Klassen Point fra pakken java.awt kan ikke clones. (Eller kan den - den's superklasse java.awt.geom.Point2D kan faktisk clones). Derfor definerer vi her en triviel subklasse af java.awt.point, som kan clones
package geometric;

/** A clonable Point */
public class Point extends java.awt.Point implements Cloneable {
  
  public Object clone(){
   try {
        return (super.clone());
       }
   catch (CloneNotSupportedException e){
        return null;
       }
  } // end clone

  public  Point(int x, int y){
    super(x,y);
  }

}

References

Interfaces i Java Core API: Serializable
Slide Note Contents Index
References 
Interfacet Serializable fra pakken java.io formidler 'letvægts persistens' af objekter i Java. Med termen 'letvægts persistens' hentyder vi til forskellen mellem faciliteten beskrevet her og en egentlig database løsning, som mere direkte er i stand til at lagre persistente objekter (en objekt-orienteret database)

En klasse C som implementerer interfacet Serializable 'signalerer' at objekter af typen C kan 'lineariseres' til et format, som tillader os at gemme objektet i en fil, eller lignende

Persistent lagring af et objekt O kan afstedkomme lagring af andre objekter, som er refereret af O

Interfacet Serializable er tomt

Program: Et programfragment som gemmer et objektnetværk på en binær fil. Det viste programfragment udskriver et array objekt literatureShelf, som er en instans af klassen LiteratureCollection (tidligere diskuteret i denne lektion).
  // gem litteratur på fil
  try {
    ObjectOutput s =  new ObjectOutputStream( new FileOutputStream( "literature.bin" ) );
    s.writeObject(literatureShelf);
    s.flush();
    s.close();
  }
  catch ( IOException e ) {
     System.out.println( "caught: " + e );
  } // slut på lagring

Program: Et programfragment som reetablerer et objektnetværk fra en binær fil. Dette programfragment indlæser objekterne, som blev udskrevet af programfragmentet vist ovenfor.
  // hent litteratur fra fil
  try {
     FileInputStream in = new FileInputStream("literature.bin");
     ObjectInputStream s = new ObjectInputStream(in);
     literatureShelf = (LiteratureCollection)s.readObject();
  }
  catch (Exception e) { 
     System.out.println ("Vi fangede: " + e);
  } // slut på hent

  • Muligheder omkring objekt serialisering:

    • Instansvariable som er mærket med modifieren 'transient' bliver ikke skrevet på filen

    • Det er muligt for en klasse at overskrive default serialisering og de-serialisering ved at implementere metoderne writeObject og readObject

References

Interfaces i forhold til abstrakte klasser
Slide Note Contents Index
References 
Interfaces og abstrakte klasser er beslægtede. Her vil vi se hvorledes slægtskabet kan beskrives

Abstrakte klasser

Interfaces

Har mulighed for at beskrive forudannoncerede metoder

Ditto

Kan bruges til at erklære variable og forudannoncerede metoder

Ditto

Kan indeholde implementerede metoder

Kan kun indeholde forudannoncerede metoder

Indgår i et énstrenget nedarvningshierarki

Kan indgå i et generelt, multipelt nedarvningshierarki

Arver altid fra Object

Intet ultimativt super-interface

Hvis man skulle tale om et 'ultimativ superinterface' skulle det være et Interface som var fuldstændigt tomt

Ikke implementerede metoder fra interfaces giver anledning til abstrakte klasser

Interfaces på tværs af klasser
Slide Note Contents Index
References 
Vi vil her markere en stærk pointe ved interfaces i kombination med klassebegrebet

Anvendelse af Interfaces som typer gør det muligt at arbejde med objekter uden af afsløre disse's klasser

  • Interfaces tillader os at sende beskeder til et objekt uden nogen som helst viden om objektets klasse

    • Tilhørsforholdet til et interfaces garanterer blot, at objekter kan besvare beskeder svarende interfacet's metoder

  • Implementation af multiple interfaces tillader et objekt at skifte rolle i løbet af sin levetid

    • Rolleskiftet er dog statisk forudbestemt af de interfaces, som objektet's klasse implementerer

Klasser bør anvendes til begrebs- og modelleringsmæssig generalisering/specialisering

Interfaces bør anvendes til at berige klasser (og dermed objekter) med andre egenskaber som enten klassificerer på tværs af klassehierarkiet, eller som kun i ringe grad klassificerer objekter

Interfaces i forhold til klasser med multipel nedarvning
Slide Note Contents Index
References 
Vi har kaldt interfaces for 'fattigmands multipel nedarvning'. Dette er sandt et stykke hen ad vejen, men interfaces bidrager også som en abstraktionsmekanisme, der 'går på tværs' af klassehierarkiet

Multipel nedarvning mellem klasser

Multipel nedarvning mellem Interfaces

Der kan arves substans

Der kan kun arves 'hensigtserklæringer'

Ofte 'let' at implementere en klasse med multiple superklasser

Ofte et stort arbejde at implementere interfaces af en klasse

Mulighed for mange, 'hårde' konflikter

Kun få og overfladiske konflikter

Tung og måske svært at forstå og gennemskue

Let og rimelig gennemskuelig

Ganske fleksibel

Meget fleksibel pga. stor uafhængighed mellem klassehierarki og interface hierarki


Collected references
Contents Index
Specialiseringer af Konto
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Specialiseringer af Konto
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Trekant specialiseringshierarkiet som del af Figur hierarkiet
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Klassehierarkier
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Klassen Konto
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Interfacet Iterator i java.util
The reference from above goes to Java API pageThe references above goes to material on the Internet
Interface Enumeration i java.util
The reference from above goes to Java API pageThe references above goes to material on the Internet
Iteratorer fra lektionen om arrays og lister
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Metoden clone i klassen Object
The reference from above goes to Java API pageThe references above goes to material on the Internet
Interface Cloneable i pakken java.lang
The reference from above goes to Java API pageThe references above goes to material on the Internet
Cloning af objekter
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
ObjectInputStream og ObjectOutputStream i kontekst
The reference above goes to a lecture note pageThe reference above points to an succeding page in the lecture notes
Object serialization
The reference above goes to a Java Tutorial pageThe references above goes to material on the Internet
Metoden readObject i klassen ObjectInputStream
The reference from above goes to Java API pageThe references above goes to material on the Internet
Metoden writeObject i klassen ObjectOutputStream
The reference from above goes to Java API pageThe references above goes to material on the Internet
Interface Serializable i pakken java.io
The reference from above goes to Java API pageThe references above goes to material on the Internet

 

Chapter 8: Design af klassehierarkier
Course home     Author home     About producing this web     Previous lecture (top)     Next lecture (top)     Previous lecture (bund)     Next lecture (bund)     
Generated: March 31, 2008, 12:08:54