Videregående programmering i Java

Dag 6 - Skabende designmønstre

Fremlæggelse af design/status for projekter

Skabende designmønstre:

Fabrikeringsmetode/Fabrik, Singleton,
Abstrakt fabrik (Toolkit), Prototype, Objektpulje

Singleton-eksempel: Forskellige slags dataforbindelser

Læsning: VP 16

Dette materiale er under Åben Dokumentlicens, se http://www.sslug.dk/linuxbog/licens.html

Skabende designmønstre

// høj kobling - klient opretter et Hjælp-objekt

Hjælp h = new Hjælp();

...

h.metode1();

h.metode2();

MEN... det kunne være at:

Det var en nedarving af Hjælp, der skulle oprettes (polymorfi)

Objektet skulle oprettet med nogle bestemte parametre i konstruktøren

Det samme objekt skulle bruges af alle klienter (en Singleton)

Eksisterende Hjælp-objekter skulle genbruges (en Objektpulje)

Skabende designmønstre

Oprettelse af objekt afgør objektets præcise type!

Dette er (for) stærk kobling i visse tilfælde

Den del af programmet (klienten) som bruger visse objekter skal ikke altid også oprette disse objekter

// høj kobling - klient opretter et Hjælp-objekt

Hjælp h = new Hjælp();

...

h.metode1();

h.metode2();

MEN... det kunne være at:

Det var en nedarving af Hjælp, der skulle oprettes (polymorfi)

Objektet skulle oprettet med nogle bestemte parametre i konstruktøren

Det samme objekt skulle bruges af alle klienter (en Singleton)

Eksisterende Hjælp-objekter skulle genbruges (en Objektpulje)

Skabende designmønstre

Fabrikeringsmetode (eng.: Factory Method)

En metode, der opretter et objekt for klienten

Afkobler (mindsker graden af bindinger) mellem

oprettelsen af nogle bestemte objekter (i ét modul)

anvendelsen af dem af (i et andet modul, klienten)

// høj kobling - klient opretter et Hjælp-objekt

//Hjælp h = new Hjælp();

// fabrikeringsmetode leverer objekt til klienten

Hjælp h = Hjælp.opretHjælp();

...

h.metode1();

h.metode2();

Det kan være at:

Det er en nedarving af Hjælp, der bliver oprettet (polymorfi)

Objektet bliver oprettet med nogle bestemte parametre i konstruktøren

Det samme objekt bliver brugt af alle klienter (en Singleton)

De eksisterende Hjælp-objekt bliver genbrugt (en Objektpulje)

Designmønstret Fabrik

(eng.: Factory)

(objekt med fabrikeringsmetode)

Problem: Klienten kan/skal ikke bestemme præcist, hvordan nogle objekter oprettes.

Løsning: Lad en Fabrik med en fabrikeringsmetode varetage oprettelsen.

// høj kobling - klient opretter et Hjælp-objekt

Image i = new Image("billede.gif"); // forkert!!

// fabrikeringsmetode leverer objekt til klienten

// this er et grafisk objekt, f.eks. applet, panel,..

Image i = this.getImage("billede.gif"); // korrekt

Image-objekter kan være forskelligt

repræsenteret afhængig af type

(GIF, JPG eller PNG) og opløsning

Designmønstret Singleton

(en klasse, der må være én og kun én instans af)

Problem: Klienten må ikke have flere objekter af en bestemt type, men skal altid bruge det samme objekt.

Løsning: Programmér sådan, at der aldrig kan oprettes mere end ét eksemplar af det pågældende objekt.

Eksempler

java.lang.Runtime (det kørende program)

java.awt.Toolkit (implementationen af grafiksystemet/AWT)

Runtime rt = Runtime.getRuntime();

// eksempler på brug af Runtime-objektet

System.out.println("Hukommelse reserveret til Java: "+rt.totalMemory());

System.out.println("Heraf ledigt: "+rt.freeMemory());

rt.gc(); // kør garbage collector

System.out.println("Nu ledigt: "+rt.freeMemory());

Toolkit tk = Toolkit.getDefaultToolkit();

// eksempler på brug af Runtime-objektet

System.out.println("Skærmstørrelse (punkter): " + tk.getScreenSize());

tk.beep(); // computeren siger bip

Image i = tk.getImage("billede.gif"); // her fungerer Toolkit som fabrik

Implementering af Singleton

Normal implementering

Privat konstruktør

Instans oprettes ved klasseindlæsning og gemmes i privat klassevariabel

Fabrikeringsmetode returnerer den private instans

Nedarvinger af Dataforbindelse?

public class Dataforbindelse

{

private static Dataforbindelse instans = new Dataforbindelse();

public static Dataforbindelse hentForbindelse() { return instans; }

private List alle;

private Dataforbindelse() { alle = new ArrayList(); }

public void sletAlleData() { alle.clear(); }

public void indsæt(Kunde k) { alle.add(k); }

public List hentAlle() { return alle; }

}

Dataforbindelse1 dbf = Dataforbindelse.hentForbindelse();

dbf.indsæt( new Kunde("Kurt",1000) );

Implementering af Singleton

Normal implementering

Privat konstruktør

Instans oprettes ved klasseindlæsning og gemmes i privat klassevariabel

Fabrikerings(klasse)metode returnerer den private instans

Andre implementeringer

Instans oprettes først når fabrikeringsmetode kaldes første gang

Fabrikeringsmetode må tjekke om instans allerede er oprettet

Trådsikkerhed kan blive et problem - fabrikeringsmetode skal være synchronized

Ingen fabrikeringsmetode, public final klassevariabel med instans

Ikke-privat konstruktør

Tillader nedarving

Konstruktør må tjekke om instans allerede er oprettet

Kast undtagelse hvis instans allerede findes

Trådsikkerhed kan blive et problem - konstruktør skal være synchronized

Fabrikeringsmetode i anden klasse

Konstruktør med pakke-synlighed

Andre implementeringer af Singleton

// Ikke-privat konstruktør

public class Dataforbindelse

{

public static Dataforbindelse instans = null;

public static synchronized Dataforbindelse hentForbindelse() {

if (instans == null) instans = new Dataforbindelse();

return instans;

}

protected Dataforbindelse() {

if (instans != null) throw new IllegalAccessException("Obj findes");

instans = this;

// Ingen fabrikeringsmetode, public final klassevariabel med instans

public class Dataforbindelse

{

public static final Dataforbindelse instans = new Dataforbindelse()

// Instans oprettes først når fabrikeringsmetode kaldes første gang

public class Dataforbindelse

{

private static Dataforbindelse instans = null;

public static synchronized Dataforbindelse hentForbindelse() {

if (instans == null) instans = new Dataforbindelse();

return instans;

}

Eksempel: Dataforbindelse

Indkapsl datalagring i klasse

Hvis man ønsker fleksibilitet omkring hvor data lagres

Start: DataforbindelseDummy, DataforbindelseFil

Slut: DataforbindelseOracle, ...

Designmønster
Abstrakt Fabrik / Toolkit

(Fabrik med abstrakt superklasse og nedarvinger, som tager sig af oprettelsen)

Problem: En Fabrik bliver uforholdsmæssigt kompliceret, fordi nogle ydre omstændigheder har stor indflydelse på, hvordan oprettelsen skal foregå.

Løsning: Lav en Abstrakt Fabrik (eng.: Abstract Factory) med en nedarving (Fabrik) for hver omstændighed.

Eksempel: java.awt.Toolkit

Fabrikerer platformsspecifik del af AWT-komponent (peer)

Nedarvinger: WindowsToolkit, LinuxToolkit, SolarisToolkit

// følgende gøres i f.eks. java.awt.Button (aldrig fra normalt program!)

package java.awt;

public class Button extends Component {

public Button() {

Toolkit tk = Toolkit.getDefaultToolkit();

ButtonPeer peer = tk.createButton(this); // platformsspecifik del!

AbstraktFabrikIF af = hentAdresseFabrik();

Adresse a = af.opretAdresse();

TelefonNr tlf = af.opretTelefonNr();

...

Haris og Thomas

Graf over trafik på netkortet (in/udgående)

Foruddefinerede regler for tilladt trafik.

Mulighed for bruger selv definere regler.

Overvåge trafik på alle porte via tcp_dump

Der gives Alert hvis regel ikke overholdes.

Alle Alert logges i en fil, som kan læses ind igen.

Henrik Quist

Henrik Quist

Atle og Anders

Atle og Anders

Atle og Anders

Preben Egelund

Designmønstret Prototype

(objekter oprettes ud fra en skabelon)

Problem: Klienten ved ikke, hvad der skal oprettes, men kan dog angive et andet objekt, som ligner det, der skal oprettes

Løsning: Brug det andet objekt som Prototype, og opret objektet ud fra prototypen

Prototyper i et tegneprogram

Palette har liste af figur-prototyper

Liste kan senere nemt udvides

Bruger kan vælge i listen

Når der vælges i paletten, anvendes det pågældende element som Prototype til objektet, der skal tegnes på skærmen

Designmønstret Objektpulje

Problem: Der er et begrænset antal resurser, som skal deles.

Problem: Der oprettes for mange objekter. Programmet er langsomt eller kører ujævnt, fordi der oprettes så mange objekter, der løbende smides væk igen.

Objekterne kunne egentligt godt genbruges i stedet for at blive smidt væk, men oprettelsen sker spredt rundt i programmet, så det er svært at koordinere.

Løsning: Lad et objekt varetage resurserne/objekterne. Lad klienter reservere og frigive objekter gennem dette objekt.

public class Objektpulje

{

private ArrayList ledige = new ArrayList();

public synchronized void sætInd(Object obj) { ledige.add(obj); }

public synchronized Object tagUd() {

if (ledige.isEmpty()) throw new RuntimeException("Ikke flere objekter!");

Object obj = ledige.remove(ledige.size()-1); // tag objekt ud af puljen

return obj;

}

}

Designmønstret Objektpulje

Andre muligheder hvis puljen løber tør for objekter

Lad puljen oprette nye objekter (evt. v.hj.a. en Fabrik): Øvelse

Lad klient 'hænge' og vente på at et objekt bliver ledigt:

public class ObjektpuljeKlientHaenger

{

private ArrayList ledige = new ArrayList();

public synchronized void sætInd(Object obj) {

ledige.add(obj);

this.notify(); // væk eventuelle ventende tråde

}

public synchronized Object tagUd() {

try {

while (ledige.isEmpty()) // så længe der ikke er ledige objekter...

{

System.out.println("Ikke flere objekter i puljen, venter...");

this.wait(); // .... vent på at blive vækket

}

Object obj = ledige.remove(ledige.size()-1); // tag objekt ud af puljen

return obj;

} catch (InterruptedException e) { return null; }

}

}

Videregående programmering i Java

Præsentatoner fra kurset

2004-08-30T12:23:21