OOP e2002 - uge 40 Disposition for (gennemgang af) afleveringsopgave IV. Teori B: Designmønstre. V. Tips til øvelser: Bold-appletten, dobbeltbufring. 1. Problemformulering 2. Design for at forklare designet vælger jeg at vise noget af implementationen under designdiskussion 3. Implementation Formål: vise hvordan man kan fokusere på design-pointer vise at der faktisk er mange principielle design pointer i noget så simpelt (?) som et kort-objekt. men jeg får mere med end der kunne være på 5 sider 'Problemformulering', Indledning Deck.shuffle() Afgrænsning: Jeg vil vise jer Kortblanding målsætning: så hurtig som mulig class Deck målsætning: nem og fleksibel tildeling af gif-filer Alle kort byttes med et vilkårligt kort til højre for kortet (eller kortet selv) F.eks. byttes kort nr. 2 med et af kortene mellem 2 og 51. public void shuffle() { for (int i = 0; i < size(); i++) swap(i, i + rand.nextint(size() - i));
class Card nem tildeling af gif-filer til kort public String tostring() { return suit.tostring() + rank.tostring(); Kortets attributter suit og rank fortæller hvilket kort det er. Ideen er at bruge attributternes værdi til at finde gif-filen, f.eks. "as.gif". Hvis kortet er spar es (Ace of Spades), udskrives "as". For at skabe stien til gif-filen, skal der blot tilføjes ".gif". class Card / ImageCard nem tildeling af gif-filer til kort (forts.) Alt det grafiske vedr. et kort er lagt i en subklasse. Fordele mere overskuelig kode mulighed for at bruge kortklassen uden grafikdelen. Princip: modularisering. "A.. system should be decomposed into a set of highly cohesive but loosely coupled modules" (Xiaoping s. 11) hvor modul = klasse forudsætter at koblingen kun er "løs" class ImageCard nem tildeling af gif-filer til kort (forts.) OOP e2002 - uge 40 Kobling: Eneste kobling til superklassen er at metoderne til at hente billeder kalder superklassens tostring(). Man kan arbejde med den ene klasse uden at behøve kigge i den anden. private Image fetchimage(applet app) { String imagepath = <codebase..> + tostring() + ".gif"; return app.getimage(app.getcodebase(), imagepath); IV. Teori B: Designmønstre. V. Tips til øvelser: Bold-appletten, dobbeltbufring. // Gif-fil skal kun hentes 1 gang, Image-objekt lagres i image-attribut.
Modularisering (class Card / class ImageCard) Designledetråde Adskil interface / implementation (interface List / class ArrayList, s. 147) Generalisering (interface Iterator, s. 209) Faktorisering (animerings-idiom, generisk animeringsapplet-klasse) Delegering (s. 139) Mere specifikt (tommelfingerregler) undgå public-kvalificerede attributter (s. 145) brug klassers kanoniske form (s. 150) undgå "skjulning"/hiding (s. 143) Adskil interface / implementation class Deck extends ArrayList { public void shuffle() { size();.. swap(..); private void swap(i,j) {.. get(..);.. set(..); java.util-pakken adskiller interfaces og implementation: class Deck bruger kun metoder der er erklæret i interface List. Derfor kan klassen let ændres til at nedarve fra en anden listeimplementation. Multipel nedarvning - kan erstattes af delegering Delegering (jf. Xiaoping s. 140) Datalogistuderende pia = new Itc-kandidat(), per = new Ruc-kombination(); pia.udskrivbeståedekurser(); per.udskrivbeståedekurser(); // fælles metoder i class Datalogistuderende if (per instanceoff) Ruc-kombination) ((Ruc-kombination)per).udskrivBasis(); // specifikke metoder for subklasser BådeOg implementerer multiple interfaces tvinger BådeOg til at implementere Ruc og Itc-metoder BådeOg har Ruc- og Itc-attributter delegering betyder at attributterne rummer metodernes reelle implementation
Animeringsidiom (ide, huskeregel) Animeringsidiom: klassestruktur class AnimationApplet extends Applet implements Runnable { Thread animationthread = null; int delay;.. // lidt flere attributter public void init() {.. public void start() {.. public void stop() {.. public void run() {.. public void paint(graphics g) {.. Animationsappletten opretter en (stærkt aggregeret) tråd, hvis eneste opgave er at udføre animationsapplettens run-metode. init(): start(): stop(): Animeringsidiom: metodernes opgaver læse parametre fra html-fil, læse applet-vinduets størrelse oprette animerings-tråd, starte tråd stoppe tråd public void run():.. pause; repaint();.. public void paint(graphics g): tegne Animeringsidiom: kontrol start() { if (animationthread == null) { animationthread = new Thread(this); animationthread.start(); public void stop() { animationthread = null; public void run() { if (animationthread!= null) {.. pause; repaint().. Tråden (run-metoden) tester, om stop() har givet stop-ordre. class Thread har egen stop()-metode, men den er usikker.
Scrolling banner: beregning af bevægelse OOP is cool paint() (Scrolling banner) paint(graphics g) { g.setfont(font); // font initialiseret andetsteds FontMetrics fm = g.getfontmetrics(); int length = fm.stringwidth(text); // banner-længde (x,y) x starter som d.width g.drawstring(text,x,y) tegner kun den del af teksten, der falder indenfor vinduet. g.drawstring("abc",-100000,20) har ingen synlig effekt. x tælles ned indtil x's værdi er så lav (stor negativ), at det indikerer at banneret er kørt helt forbi. x -= offset; if (x < - length) x = d.width; // starte forfra g.setcolor(color.black); g.fillrect(0,0,d.width, d.height); g.setcolor(color.green); g.drawstring(text, x, y); Applet-konteksten: ApplicationListener er en metafor for den del af konteksten, der lytter til hændelser genereret af applikationen (appletten), dvs. kald af repaint(). SystemListener lytter til hændelser genereret af systemomgivelserne, f.eks. ved at brugeren resizer vinduet eller browser videre. Applet-konteksten (flere detaljer)
repaint() --> update(), paint() Når ApplicationListener/SystemListener kalder paint()/update(): 0. Muligvis ventes der lidt først. 1. Graphics g = det nuværende billede (det sidst tegnede); 2. kald af enten update(g) eller paint(g); // 2 og 3 3. tegn(g); // kan foregå samtidigt Container superklasse opfanges kald af update()/paint() hvis de ikke overskrives i subklasser: public void update(grahpics g) { g.setcolor(getbackground()); // vælger baggrundsfarven g.clearrect(0, 0, width, height); // udfylder g med farven g.setcolor(getforeground()); // vælger forgrundsfarven paint(g); public void paint(graphics g) { {kalder paint() i alle subkomponenter OOP e2002 - uge 40 IV. Teori B: Designmønstre. V. Tips til øvelser: Bold-appletten, dobbeltbufring. Nedarvning fra generisk animerings-klasse Konstruktion af animerings-appletter som subklasser (a la XP s. 185) class DigitalClock extends AnimationApplet { DigitalClock() { setdelay(1000) ; public void paint(graphics g) {.. som før.. ; Font font =..; Color color =..; // hvor er init(), start(), stop(), run() etc.? class AnimationApplet (XP s. 184) [abstract] class AnimationApplet extends Applet implements Runnable { Thread animationthread = null; int delay; setdelay(int d) {..; public void init() {.. public void start() {.. public void stop() {.. public void run() {.. // ingen paint() // ny: setdelay()
"faktorisering ved nedarvning" (a la XP s. 182) Faktorisering Før: class DigitalClock { metode1(); metode2(); metodedc(); class ScrollingBanner { metode1(); metode2() metodesb(); Nu: class AnimationApplet { metode1(); metode2(); class DigitalClock extends AnimationApplet{ metodedc(); class ScrollingBanner extends AnimationApplet { metodesb(); "Faktorisering" kan opfattes som nedbrydning i et antal egenskaber, der går igen mellem flere klasser. I matematik er faktorisering opdeler af et tal i faktorer: 6 = 2*3 14 = 2*7 (2 er en fælles faktor) De fælles faktorer/metoder kan implementeres i en abstrakt klasse. En abstrakt klasse er en klasse, der skal subklasses før der kan skabes instanser af den. Faktorisering kan også realiseres vhja. delegering. Lad os faktorisere dobbelt-bufrede appletter! Formål: at undgå flimmer flimmer kommer når vi maler (langsomt) i et grafik-objekt, fordi konteksten tegner grafik-objektet på skærmen samtidig Flimmer kan reduceres ved at male i et ekstra ("dobbelt") grafik-objekt, som først overføres til konteksten når vi er færdige. Det viser sig, at ved dobbelt-bufring bør man overskrive update() i stedet for paint(). I konteksten kaldes paint() af update(), efter update() har "forbehandlet" grafikobjektet ved at overmale det med baggrundsfarven. Vi har ikke brug for forbehandlingen da vi overskriver det gamle grafikobjekt med vores grafik-buffer, og derfor selv skal lave baggrunden. AnimationApplet og DBAnimationApplet (XP s. 191) AnimationApplet tager sig af alt vedr. animering (dog ikke dobbelt-bufring) Oprettelse af en separat tråd, kald af sleep()/repaint() fra trådens run(), m.m. Subklasser skal blot definere paint() samt evt. justere delay. DBAnimationApplet har sin egen final update(), der kalder paintframe(), der er en abstrakt metode.
Konstruktion af class DBAnimationApplet Nedarver fra AnimationApplet, derfor kun konstruere: initialisering omdefinering af paint()/update() til at bruge dobbeltbuffer endvidere foreslår XP at gøre dobbeltbufringen valgfri (?) Initialisering skal omfatte både: initialisering i appletten/subklassen initialisering af dobbeltbuffer Maling skal omfatte både: selve malerarbejdet i appletten/subklassen dobbeltbufringen i DBAnimationApplet class DBAnimationApplet (frit efter XP s. 192) class DBAnimationApplet extends AnimationApplet { Graphics offscreengraphics; // "papiret" Image offscreenimage; // "billedet" // (en matrix af pixels) final public void init() {.. ; void initanimator() {; // overskrives formentlig final public void update(graphics g) {..; abstract void paintframe(graphics g) {; // skal overskrives DBAnimationApplet er lavet ud fra et "mistillidsprincip", hvor man garderer sig mod at subklassen/appletten ikke læser brugervejledningen! Initialisering Maling Graphics offscreengraphics; Image offscreenimage; final public void init() { Dimension d = getsize(); offscreenimage = createimage(d.width, d.height); offscreengraphics = offscreenimage.getgraphics(); initanimator(); Graphics offscreengraphics; Image offscreenimage; final public void update(graphics g) { paintframe(offscreengraphics); g.drawimage(offscreenimage); // g "overskrives" abstract void paintframe(graphics g) { void initanimator() { // overskrives formentlig
update() vs. paint(): hvilken skal overskrives i Applet-subklasser? OOP e2002 - uge 40 Hvis subklasser overskriver update(): skal de selv sørge for at gentegne hele baggrunden men så slipper de for at vente på at appletkonteksten gentegner baggrunden. Hvis man bruger dobbelt-bufring: bør man overskrive update() fordi man alligevel selv skal tegne baggrunden (da man jo ikke tegner i det grafikobjekt der er skabt i konteksten, men tværtimod overskriver det med ens egen "buffer") IV. Teori B: Designmønstre. UDSKUDT TIL NÆSTE GANG V. Tips til øvelser: Bold-appletten, dobbeltbufring. OOP e2002 - uge 40 BouncingBall (BoldAppletten) IV. Teori B: Designmønstre. V. Tips til øvelser: Bold-appletten class BouncingBall extends DBAnimationApplet { int x, y; // boldens koordinater int dx, dy; // boldens bevægelse void initanimator() { {vælg startposition for bold void paintframe(graphics g) { {hvis bolden har ramt kant, vend retning {bevæg bold {tegn bold