From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001 From: Sven Eisenhauer Date: Fri, 10 Nov 2023 15:11:48 +0100 Subject: add new repo --- .../hjp5/html/k100281.html | 621 +++++++++++++++++++++ 1 file changed, 621 insertions(+) create mode 100644 Master/Reference Architectures and Patterns/hjp5/html/k100281.html (limited to 'Master/Reference Architectures and Patterns/hjp5/html/k100281.html') diff --git a/Master/Reference Architectures and Patterns/hjp5/html/k100281.html b/Master/Reference Architectures and Patterns/hjp5/html/k100281.html new file mode 100644 index 0000000..0909b08 --- /dev/null +++ b/Master/Reference Architectures and Patterns/hjp5/html/k100281.html @@ -0,0 +1,621 @@ + + + +Handbuch der Java-Programmierung, 5. Auflage + + + + + + + + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage +
 <<  +  <   +  >   + >>  + API  +Kapitel 44 - Beans +
+
+ + + + +

44.2 Entwurf einer einfachen Bean

+
+ +
+ +

+Wir wollen uns in diesem Abschnitt mit dem Entwurf einer einfachen +Bean beschäftigen. Dazu werden wir eine Klasse LightBulb +entwerfen, die eine kleine Glühlampe grafisch darstellt. Sie +kann wahlweise an- oder ausgeschaltet werden. Diese Klasse wird alle +notwendigen Eigenschaften einer Bean aufweisen und kann im GUI-Designer +und im laufenden Programm verwendet werden. + + + + +

44.2.1 Grundsätzliche Architektur

+ +

+Da wir eine GUI-Komponente realisieren wollen, folgen wir analog der +in Kapitel 33 beschriebenen +Vorgehensweise und leiten unsere Klasse LightBulb +aus der Klasse Canvas +des Pakets java.awt +ab. Um die Eigenschaft der Serialisierbarkeit zu erfüllen, implementiert +die Klasse das Interface Serializable. +Der Anschaltzustand wird in der Instanzvariablen lighton +festgehalten: + + +

+ + + + +
+ +
+001 import java.awt.*;
+002 import java.awt.event.*;
+003 import java.io.*;
+004 import java.beans.*;
+005 
+006 public class LightBulb
+007 extends Canvas
+008 implements Serializable
+009 {
+010   protected boolean lighton;
+011   transient protected Image   offimage;
+012   transient protected Image   onimage;
+013   ...
+014 }
+
+
+ +Listing 44.1: Deklaration der Klasse LightBulb

+ + + + +

44.2.2 Grafische Darstellung

+ +

+Die grafische Darstellung der Glühbirne soll durch das Anzeigen +von Bitmaps erfolgen, die bei der Instanzierung aus zwei gif-Dateien +bulb1.gif und bulb2.gif +geladen werden. Abhängig vom Zustand der Variable lighton +wird in der überlagerten paint-Methode +jeweils eine der beiden Bitmaps angezeigt. Das Verfahren entspricht +im wesentlichen dem in Abschnitt 34.1.2 +beschriebenen. Auch die Methoden getPreferredSize +und getMinimumSize +werden überlagert, damit die Komponente einem eventuell vorhandenen +Layoutmanager die gewünschte Größe (in diesem Fall +40 mal 40 Pixel) mitteilen kann. + +

+Etwas anders als bisher beschrieben arbeitet die Routine zum Laden +der Bilddateien. Damit die Bilddatei auch gefunden wird, wenn die +Klasse aus einer .jar-Datei geladen wurde +(das ist beispielsweise beim Laden von serialisierten Beans oder beim +Import in einen GUI-Designer der Fall), kann nicht einfach der Dateiname +an createImage +bzw. getImage +übergeben werden. Statt dessen konstruieren wir mit Hilfe des +Klassenobjekts unserer Bean und dessen Methode getResource +ein URL-Objekt, +das wir an createImage übergeben +können: + + +

+ + + + +
+ +
+001 private Image getImageResource(String name)
+002 {
+003   Image img = null;
+004   try {
+005     java.net.URL url = getClass().getResource(name);
+006     img = getToolkit().createImage(url);
+007     MediaTracker mt = new MediaTracker(this);
+008     mt.addImage(img, 0);
+009     try {
+010       //Warten, bis das Image vollständig geladen ist,
+011       mt.waitForAll();
+012     } catch (InterruptedException e) {
+013       //nothing
+014     }
+015   } catch (Exception e) {
+016     System.err.println(e.toString());
+017   }
+018   return img;
+019 }
+
+
+ +Listing 44.2: Laden einer Image-Ressource

+ +

+Diese Vorgehensweise basiert darauf, dass jede geladene Klasse ihren +Classloader (also das Objekt, das für +das Laden der Klasse verantwortlich war) kennt und an diesen Aufrufe +zum Laden von Ressourcen delegieren kann. Der beim Laden eines Objekts +aus einer .jar-Datei verwendete Classloader +unterscheidet sich dabei sehr wohl von dem Bootstrap Loader, +der System- und Anwendungsklassen aus .class-Dateien +lädt. Diese Unterscheidung wird in dem von getResource +gelieferten URL gekapselt und vom AWT-Toolkit beim Aufruf von createImage +aufgelöst. +

+ + + + + + + + + +
+ +

+Nach dem Aufruf von createImage +sorgt ein MediaTracker +dafür, das die Bilddateien erst vollständig geladen werden, +bevor die Methode terminiert. Diese Technik verhindert, dass paint +aufgerufen wird, während die Image-Objekte +noch nicht vollständig initialisiert sind. Details dazu wurden +in Abschnitt 34.1.1 +vorgestellt.

+ + + + +
 Hinweis 
+
+ + + + +

44.2.3 Eigenschaften

+ +

+Wie im einleitenden Abschnitt dargelegt, sind Eigenschaften +ein wesentliches Designmerkmal von Beans. Eine Eigenschaft ist eigentlich +nur eine Membervariable, die über öffentliche Methoden gelesen +und geschrieben werden kann. Eine Bean kann beliebig viele Eigenschaften +haben, jede von ihnen besitzt einen Namen und einen Datentyp. Die +Bean-Designkonventionen schreiben vor, dass auf eine Eigenschaft mit +dem Namen name und dem Datentyp typ über folgende +Methoden zugegriffen werden soll: +

+ + + + +
+ +
+public typ getName();
+
+public void setName(typ newValue);
+
+
+
+

+ + + + + + + + + +
+ +

+Diese beiden Methoden bezeichnet man auch als getter- +und setter-Methoden.

+ + + + +
 Hinweis 
+
+ +

+Unsere Beispiel-Bean hat eine einzige Eigenschaft lightOn vom +Typ boolean. Ihre getter-/setter-Methoden +haben demnach folgende Signatur (der erste Buchstabe des Eigenschaftsnamens +wird großgeschrieben, da er hinter dem »get« bzw. +»set« steht): + +

+public boolean getLightOn();
+
+public void setLightOn(boolean newvalue);
+
+ + +

+Auf diese Weise können getter- und setter-Methoden für alle +primitiven Datentypen geschrieben werden. Der GUI-Designer erkennt +Eigenschaftennamen und -typen anhand der Signaturen und stellt automatisch +einen passenden Editor dafür zur Verfügung. + + + + +

Objekte als Eigenschaften

+ +

+Neben primitiven Typen ist auch die Übergabe von Objekttypen +erlaubt. Die Signaturkonventionen entsprechen genau denen von primitiven +Typen. Bei Objekteigenschaften kann allerdings nicht unbedingt davon +ausgegangen werden, dass der GUI-Designer einen geeigneten Editor +zur Verfügung stellen kann. Zwar besitzt der GUI-Designer für +die häufig benötigten Objekttypen Color +und Font standardmäßig +geeignete Editoren. Bei einem selbstdefinierten Objekttyp ist das +natürlich nicht der Fall. Hier muss der Entwickler nötigenfalls +selbst einen Editor entwickeln und dem Designer zur Verfügung +stellen. Wir werden in Abschnitt 44.6.2 +zeigen, wie das gemacht wird. + + + + +

Indizierte Eigenschaften

+ +

+Anstelle eines Einzelwertes kann eine Eigenschaft auch durch ein Array +von Werten repräsentiert werden. Sie wird in diesem Fall als +indizierte Eigenschaft bezeichnet. +Die getter-/setter-Methoden sehen dann so aus: +

+ + + + +
+ +
+public typ getName(int index);
+
+public void setName(int index, typ newValue);
+
+
+
+ +

+Es werden also keine Arrays übergeben, sondern die Methoden erwarten +jeweils den Index der gewünschten Eigenschaft als zusätzliches +Argument. Für das Einhalten der Arraygrenzen ist der Aufrufer +selbst verantwortlich. Ist die Arraygröße variabel, könnte +die Bean sie in einer zweiten Eigenschaft festhalten und über +eigene getter-/setter-Methoden verfügbar machen. +

+ + + + + + + + + +
+ +

+Auch indizierte Eigenschaften werden vom GUI-Designer automatisch +erkannt und sollten zum Aufruf eines geeigneten Editors führen. +Die Beanbox selbst (also die von SUN zur Verfügung gestellte +Referenzimplementierung eines GUI-Designers), auf die wir in Abschnitt 44.3 +eingehen werden, kann allerdings nicht mit indizierten Eigenschaften +umgehen.

+ + + + +
 Hinweis 
+
+ + + + +

44.2.4 Implementierung

+ +

+Nach diesen Vorbemerkungen ist die Implementierung der Bean zur Darstellung +der Glühbirne keine große Hürde mehr: + + +

+ + + + + +
+ +
+001 /* LightBulb.java */
+002 
+003 import java.awt.*;
+004 import java.awt.event.*;
+005 import java.io.*;
+006 import java.beans.*;
+007 
+008 public class LightBulb
+009 extends Canvas
+010 implements Serializable
+011 {
+012   //Instanzvariablen
+013   protected boolean lighton;
+014   transient protected Image offimage;
+015   transient protected Image onimage;
+016 
+017   //Methoden
+018   public LightBulb()
+019   {
+020     lighton = false;
+021     initTransientState();
+022   }
+023 
+024   //Getter/Setter Licht an/aus
+025   public void setLightOn(boolean on)
+026   {
+027     if (on != this.lighton) {
+028       this.lighton = on;
+029       repaint();
+030     }
+031   }
+032 
+033   public boolean getLightOn()
+034   {
+035     return this.lighton;
+036   }
+037 
+038   public void toggleLight()
+039   {
+040     setLightOn(!getLightOn());
+041   }
+042 
+043   //Implementierung der Oberfläche
+044   public void paint(Graphics g)
+045   {
+046     int width = getSize().width;
+047     int height = getSize().height;
+048     int xpos = 0;
+049     if (width > 40) {
+050       xpos = (width - 40) / 2;
+051     }
+052     int ypos = 0;
+053     if (height > 40) {
+054       ypos = (height - 40) / 2;
+055     }
+056     g.drawImage(
+057       (this.lighton ? onimage : offimage),
+058       xpos,
+059       ypos,
+060       this
+061     );
+062   }
+063 
+064   public Dimension getPreferredSize()
+065   {
+066     return new Dimension(40, 40);
+067   }
+068 
+069   public Dimension getMinimumSize()
+070   {
+071     return new Dimension(40, 40);
+072   }
+073 
+074   //Private Methoden
+075   private void initTransientState()
+076   {
+077     offimage = getImageResource("bulb1.gif");
+078     onimage  = getImageResource("bulb2.gif");
+079   }
+080 
+081   private void readObject(ObjectInputStream stream)
+082   throws IOException, ClassNotFoundException
+083   {
+084     stream.defaultReadObject();
+085     initTransientState();
+086   }
+087 
+088   private Image getImageResource(String name)
+089   {
+090     Image img = null;
+091     try {
+092       java.net.URL url = getClass().getResource(name);
+093       img = getToolkit().createImage(url);
+094     } catch (Exception e) {
+095       System.err.println(e.toString());
+096     }
+097     return img;
+098   }
+099 }
+
+
+LightBulb.java
+ +Listing 44.3: Die Bean zur Anzeige einer Glühbirne

+ +

+Der Konstruktor initialisiert zunächst die Zustandsvariable lighton +und ruft dann die Methode initTransientState +auf, um die beiden gif-Dateien zu laden. Durch Aufruf von setLightOn +kann die Beleuchtung wahlweise an- oder ausgeschaltet werden; getLightOn +liefert den aktuellen Zustand. In paint +wird - abhängig vom aktuellen Zustand - jeweils eines der beiden +Images ausgegeben. Die Umrechnungsroutinen dienen dazu, die Images +zentriert auszugeben, wenn mehr Platz als nötig zur Verfügung +steht. +

+ + + + + + + + + +
+ +

+Bemerkenswert ist, dass die Methode readObject +überlagert wurde. Sie wird immer dann aufgerufen, wenn die zuvor +serialisierte Bean per Deserialisierung instanziert wird. In diesem +Fall würde nämlich der Konstruktor des Objekts gar nicht +aufgerufen werden (siehe Abschnitt 41.1.3) +und die Image-Variablen blieben +uninitialisiert. Ihre Initialisierung haben wir deshalb in die Methode +initTransientState verlagert, +die sowohl aus dem Konstruktor als auch aus readObject +aufgerufen wird. Damit wird die Bean in beiden Fällen (Instanzierung +per new und Deserialisierung) +vollständig initialisiert. In seiner eigentlichen Funktion ruft +readObject lediglich defaultReadObject +auf, um die Standard-Deserialisierung auszuführen.

+ + + + +
 Hinweis 
+
+ + + + +

44.2.5 Verwendung der Bean

+ +

+Zum Abschluss wollen wir uns ansehen, wie die erstellte Bean in ein +einfaches Programm eingebunden werden kann. Dazu bedienen wir uns +exakt der Techniken, die bereits in den Kapiteln 31 +bis 34 beschrieben +wurden. Tatsächlich unterscheidet sich die Verwendung einer selbstentwickelten +Bean nicht vom Einbinden einer vordefinierten Komponente. + + +

+ + + + + +
+ +
+001 /* Listing4404.java */
+002 
+003 import java.awt.*;
+004 import java.awt.event.*;
+005 
+006 public class Listing4404
+007 extends Frame
+008 {
+009   public Listing4404()
+010   {
+011     super("Bean einbinden");
+012     setLayout(new FlowLayout());
+013     setBackground(Color.lightGray);
+014     LightBulb bulb1 = new LightBulb();
+015     bulb1.setLightOn(false);
+016     add(bulb1);
+017     LightBulb bulb2 = new LightBulb();
+018     bulb2.setLightOn(true);
+019     add(bulb2);
+020     addWindowListener(
+021       new WindowAdapter() {
+022         public void windowClosing(WindowEvent event)
+023         {
+024           System.exit(0);
+025         }
+026       }
+027     );
+028   }
+029 
+030   public static void main(String[] args)
+031   {
+032     Listing4404 frm = new Listing4404();
+033     frm.setLocation(100, 100);
+034     frm.pack();
+035     frm.setVisible(true);
+036   }
+037 }
+
+
+Listing4404.java
+ +Listing 44.4: Einbinden einer einfachen Bean

+ +

+Die Ausgabe des Programms sieht wie folgt aus: +

+ + +

+ +

+Abbildung 44.1: Die Glühlampen-Bean

+
+ + + +
 Titel  + Inhalt  + Suchen  + Index  + DOC  +Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 +
 <<  +  <   +  >   + >>  + API  +© 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de +
+ + + -- cgit v1.2.3