Fördjupande uppsats i datalogi

Relevanta dokument
Arv. Fundamental objekt-orienterad teknik. arv i Java modifieraren protected Lägga till och modifiera metoder med hjälp av arv Klass hierarkier

Objektorienterad programmering

Objekt-orienterad programmering och design. DIT953 Niklas Broberg, 2018

F8 - Arv. ID1004 Objektorienterad programmering Fredrik Kilander

Introduktion till arv

Objektorienterade programmeringsspråk. Objektorienterade språk. Den objekt-orienterade modellen. Jämför med icke-oo

Föreläsning 8 - del 2: Objektorienterad programmering - avancerat

Principles of subclasses. Objekt-orienterad programmering och design Alex Gerdes, 2018

Outline. Objektorienterad Programmering (TDDC77) Signatur. Klassen calculator. Överlagring (overloading) Arv (inheritance) Ahmed Rezine

Objektorienterad Programmering (TDDC77)

Objekt-orienterad Programmering och Design. TDA551 Alex Gerdes, HT-2016

Laboration 1: Figurer i hierarki

Objektorienterad Programkonstruktion. Föreläsning 6 23 nov 2015

Objektorienterad Programkonstruktion, DD1346 FACIT. Tentamen , kl

Designmönster/Design patterns

Vad handlar kursen om? Algoritmer och datastrukturer. Vad handlar kursen om? Vad handlar kursen om?

Tentamen. 2D4135 vt 2005 Objektorienterad programmering, design och analys med Java Lördagen den 28 maj 2005 kl

Kopiering av objekt i Java

Objektorienterad programmering med Java, Generics

Klient/server. Översikt. Lektion 1: Webbtekniker från Microsoft. Webbteknik från Microsoft. Klient/server. Designmönster. Utrullning.

Objekt, klasser. Tillstånd Signatur Kommunikation Typ. Fält, parametrar och lokala variabler. Konstruktorer Metoder DAVA15

Lösningar till tentamen i EDAF25

Arv och polymorfism i Java

2I1049 Föreläsning 5. Objektorientering. Objektorientering. Klasserna ordnas i en hierarki som motsvarar deras inbördes ordning

Objektorienterad programmering, allmänt

Viktiga egenskaper hos ett program (Meyer): Objektorienterad programmering, allmänt. Vilka egenskaper vill vi att våra program ska ha?

Inkapsling (encapsulation)

Static vs Dynamic binding Polymorfism. Objekt-orienterad programmering och design (DIT953) Niklas Broberg, 2018

Typhierarkier del 1 Gränssnitt, ärvning mellan gränssnitt, ärvning mellan klasser

Objektorienterad Programkonstruktion

Repetition av OOP- och Javabegrepp

Tentamen i EDAF25. 1 juni Skrivtid: Skriv inte med färgpenna enda tillåtna färg är svart/blyerts.

Mer OOP. Variation i typ. Medlen repetition. Generiska klasser. Gränssnitt - Interface. Mer om klasser Några exempel UML

Objektorienterad Programkonstruktion. Föreläsning jan 2016

Akronymer. CD5130 OOP, fk. Mjukvarumönster. Mjukvarumönster. Mjukvarumönster, forts. Mjukvarumönster, forts

Repetition av OOP- och Javabegrepp

DAT043 - Föreläsning 7

Tentamen. 2D4135 vt 2004 Objektorienterad programmering, design och analys med Java Torsdagen den 3 juni 2004 kl

TDDD78, TDDE30, 729A Typhierarkier del 3 När och hur vill vi använda dem? Några Best Practices

Laboration 2: Designmönster

Objekt-orienterad Programmering och Design. TDA552 Alex Gerdes, HT-2018

Föreläsning 15: Repetition DVGA02

Objektorienterad programmering. Grundläggande begrepp

Introduktion till objektorientering. Vad är objektorientering egentligen? Hur relaterar det till datatyper? Hur relaterar det till verkligheten?

DAT043 - föreläsning 8

Föreläsning 8. Designmönster

Obs! Inget ur Javas standardbibliotek får användas i ett svar (om det inte står att man får det).

Principles of subclasses Objekt-orienterad programmering och design (DIT953) Niklas Broberg, 2018

Objektorienterad Programkonstruktion. Föreläsning 9 30 nov 2016

Objektorienterad programmering E. Telefonboken, än en gång. Gränssnitt. Telefonboken med gränssnitt specificerat, del 1.

Läs detta! Uppgifterna är inte avsiktligt ordnade efter svårighetsgrad. Skriv ditt idnummer på varje blad (så att vi inte slarvar bort dem).

Grundläggande programmering, STS 1, VT Sven Sandberg. Föreläsning 14

TDDE10 m.fl. Objektorienterad programmering i Java Föreläsning 6 Erik Nilsson, Institutionen för Datavetenskap, LiU

Classes och Interfaces, Objects och References, Initialization

OOMPA 2D1359 Föreläsning 2

Outline. Objektorienterad Programmering (TDDC77) Att instansiera en klass. Objekt. Instansiering. Åtkomst. Abstrakt datatyp.

F9 - Polymorfism. ID1004 Objektorienterad programmering Fredrik Kilander

TDDE10 m.fl. Objektorienterad programmering i Java Föreläsning 6 Erik Nilsson, Institutionen för Datavetenskap, LiU

Tentamen i TDP004 Objektorienterad Programmering Lösningsförslag

Begreppet subtyp/supertyp i Java. Mera om generik. Generik och arv. Generik och arv. Innehåll

Laboration 2: Designmönster

Objektorienterad konstruktion

Innehåll. dynamisk bindning. och programmering CRC) u Arv, polymorfi och

Static vs Dynamic binding Polymorfism. Objekt-orienterad programmering och design Alex Gerdes, 2016

Webbtjänster med API er

UML. Översikt UML. Relationer mellan klasser. A är ett aggregerat av B:n. Kontor aggregat av Enheter. 12 olika diagramtyper, bl.a.

Lösningar till Fiktiv Tentamen på kursen. 2D4135 Objektorienterad programmering, design och analys med Java vt2004. Teoridel

Design Patterns. En kort introduktion

Föreläsning 10. ADT:er och datastrukturer

kl Tentaupplägg

Det här dokumentet är till för att ge en översikt över ASP.NET MVC samt hur WCF Services används från.net applikationer.

Lösningsförslag till tentamen

TDDE10 TDDE11, 725G90. Objektorienterad programmering i Java, Föreläsning 3 Erik Nilsson, Institutionen för Datavetenskap, LiU

Lösningar till tentamen i EDAF25

Classes och Interfaces, Objects och References Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2016

Objektorienterad Programmering (TDDC77)

Objektorienterad programmering Föreläsning 8. Copyright Mahmud Al Hakim Agenda (halvdag)

Outline. Objektorienterad Programmering (TDDC77) Åsidosättning. Signatur. Åsidosättning. Abstrakta klasser. Ahmed Rezine.

Objektorienterad Programkonstruktion, DD1346. Tentamen , kl

Programmeringsteknik II - HT18. Föreläsning 6: Grafik och händelsestyrda program med användargränssnitt (och Java-interface) Johan Öfverstedt

Klasshierarkier - repetition

Föreläsningsmaterial (Arv) Skrivet av Andreas Lund

Objekt-orienterad programmering. Klassbegreppet och C++ UML. UMLs fördelar

Övningen vill visa på vikten av valet av datastruktur, trots att de ofta erbjuder samma funktionalitet genom sina gränssnitt.

Abstrakta Klasser 2. Kodning är bara en liten del i programvaruutvecklingen 6% 1% 6% Abstrakta Klasser - deklaration. Programutveckling sker i faser

Objektorienterad Programkonstruktion. Föreläsning 4 8 nov 2016

DIAGNOSTISKT PROV. Tid. Hjälpmedel. Antaganden. Rättning. Övrigt. Diagnostiskt Prov. Klockan Inga

TDDD78, TDDE30, 729A Typhierarkier del 2 Vad krävs? Hur fungerar det?

Det är principer och idéer som är viktiga. Skriv så att du övertygar rättaren om att du har förstått dessa även om detaljer kan vara felaktiga.

Tentamen. DD2385 Programutvecklingsteknik vt 2013 Onsdagen den 22 maj 2013 kl Hjälpmedel: penna, suddgummi, linjal

Föreläsning 13 Innehåll

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 11 Jonas Lindgren, Institutionen för Datavetenskap, LiU

Designmönster, introduktion. Vad är det? Varför skall man använda mönster?

Introduktion till objektorientering. Vad är objektorientering egentligen? Hur relaterar det till datatyper? Hur relaterar det till verkligheten?

Konstruktion av klasser med klasser

Undantag. Engelska: exceptions. Skansholm: exceptionella händelser

Arv. Objektorienterad och komponentbaserad programmering

Lambdas. (och fler design patterns) Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2017

Integritetsprincipen. Objektorienterad modellering och diskreta strukturer / design

Objektorientering - Arv och polymorfi. Eric Elfving Institutionen för datavetenskap

Transkript:

Fördjupande uppsats i datalogi Design Patterns: Elements of Reusable Object-Oriented Software Inledning Jag har läst boken Design Patterns: Elements of Reusable Object-Oriented Software. Boken, som myntade begreppet Design Pattern, kom först ut år 1995. Och den har sedan dess sålt i mer än 500000 exemplar världen över. Den är rankad på andra plats av Amazon Best Sellers inom datalogi[1]. Åsikter verkar gå isär när det gäller att kvantifiera bokens betydelse för mjukvaruindustrin i allmänhet. Vissa värderar den säkert högre än andra[4]. Dock är det nästintill omöjligt att idag vara mjukvaruingenjör någon längre tid utan att komma i kontakt med begrepp som Composite, Singelton och Abstract Factory. I de flesta fall är det begrepp man förväntas känna till, och fast de har studerats i en mängd olika böcker så var det i och med boken Design Patterns som begreppen först föddes. Bakgrund Uppsatsen vänder sig till mjukvaruutvecklare eller blivande utvecklare som tänkt läsa boken Design Patterns, eller någon liknande bok, men av någon anledning inte kommit till skott, och i allmänhet vill veta mer om konceptet Design Patterns. I och med detta antas målgruppen antas vara relativt duktiga programmerare. Bokens exempel är främst i C++ och Smalltalk. I mina exempel håller jag mig till Java. Av den anledning hjälper det om läsaren är bekant med Java, men eftersom språkkonstruktionerna som används är så pass simpla räcker det troligtvis med att kunna ett godtyckligt objektorienterat språk för att förstå exemplen. Eftersom antalet ord som jag har till mitt förfogande är betydligt färre än vad boken hade kommer jag gå igenom en Desing Pattern i detalj, nämligen den så kallade Composite. Jag valde Composite eftersom den enligt mig är den Design Pattern som mest inbegriper det författarna kallar the second principle of object-oriented design : Favor object composition over class inheritance. För mig var citatet ovan ganska förvånande. Jag hade alltid sett arv som något mycket fint. Dock så hade jag också stundtals brottats med problem när det gäller arv. Först nu efter att ha läst boken kan jag tydligt formulera problemet. Och det är något som boken påpekar om och om igen, nämligen den statiska sammansättningen som arv medför. Ett uppenbart exempel är Javas klassbibliotek för att hantera in och utmatning. Det finns en bas-klass för att hantera alla typer av inläsning av inmatningsströmmar som vi kallar. En mängd olika klasser som specialiserar sig på att läsa olika typer av strömmar ärver från : CharArray, String, File, och så vidare. Ofta när man läser från strömmar är det i ens intresse att buffra inläsningen. Det är dock en egenskap som ska vara valfri för varje instans av en skapad läsare. En arvsbaserad lösning är att skapa en ny klass, Buffered, och låta varje specialiserad typ av ärva från den, det vill säga: BufferedCharArray, BufferedString, BufferedFile, och så vidare. Klassdiagrammet ser då ut på följande sätt: 1

CharArray String File Buffered BufferedChar Array Buffered String InputStream Figur 1: Klassdiagram för lösningen som föreslogs ovan. Pilen symboliserar arv. Buffered File Strukturen som visas i figur 1 är, som läsaren säkert redan uppmärksammat, katastrofal ur upprepningssynpunkt. Funktionaliteten som skiljer de olika läsarna åt behöver upprepas i två separata klasser per specialisering (en buffrad och en icke-buffrad). En annan lösning, som också tar hjälp av arv, vore att låta en Buffered-subklass ärva från varje specialisering. Strukturen blir då: CharArray String File BufferedChar Array Figur 2: Den andra lösningen som föreslogs ovan. Buffered String InputStream BufferedFile Inte heller lösningen ovan är särskilt fördelaktig ur upprepningssynpunkt. Visserligen känns denna lösning mer naturlig än den föregående, men den medför ändå en upprepning av koden som möjliggör buffring för varje ny typ av inmatningsström. Istället löser man det i Java med composition. Det vill säga en Buffered ärver från (som i lösning 1), men istället för att låta olika specialiseringar ärva från Buffered låter man Buffered innehålla (compose) en. Buffered är en tillämping av en särskild Design Pattern, nämligen Decorator (sida 175 i boken). Buffered dekorerar en valfri given med buffringsfunktionalitet. En Buffered kan instansieras med en File: reader = new Buffered(new File(new File("foo.txt"))); Lika väl som den kan instansieras med en String: reader = new Buffered(new String("foo")); Den valda strukturen ser ut på följande sätt: 2

CharArray String File Buffered Figur 3: Lösningen med Decorator som finns i Java. Diamanten symboliserar composition. Resultatet är att man slipper implementera ytterligare tre klasser och det finns ingen uppenbar upprepning av logik. Lösningen blir desto mer överlägsen när man vill implementera ytterligare någon valfri egenskap i likhet med buffring. Av en slump så hände det mig bara några veckor sedan. Jag ville implementera en läsare som bara läste rader som matchade ett givet regular expression. Jag kallade klassen Grep, och på samma sätt som Buffered innehåller (compose) den en. Det gör att vi kan skapa en buffrad Grep som läser från fil: reader = new Grep(new Buffered(new File(new File("foo.txt")))); och en obuffrad Grep som laser från en sträng: reader = new Grep(new String("foo")); Hade strukturen från början sett ut som den i figur 2, och jag hade fortsatt på samma spår, hade jag behövt implementera GrepBufferedFile, GrepFile, och så vidare. I längden är en sådan lösning ohållbar om man vill kunna lägga till valfri funktionalitet till varje klass. När man läst redogörelsen ovan får man nästan känslan av att författarna förespråkar composition framför arv i alla situationer och att arv aldrig borde tillämpas. Så är absolut inte fallet, tvärtom så innehåller många Design Patterns arv i någon form. Men författarna tycker sig se ett överutnyttjande av arv när istället compositon skulle ge en mer dynamisk klasstruktur som lämpar sig bättre för eventuella utökningar. Resterande delar av den här uppsatsen är ordnade på följande sätt: först redogörs Composite för, sedan följer några exempel på Design Patterns (mer moderna än de som nämns i boken) som jag själv stött på, och sist kommer en summering och avslutning. Composite Composite heter den Design Pattern som jag valt att fokusera på. Composite, i likhet med Decorator, involverar som sagt composition. Huvudidén med Composite är att låta enstaka objekt behandlas på samma sätt som mängder eller snarare hierarkier av objekt. Det hela uppnås med att alla klasser som deltar implementerar en abstrakt klass som vi kallar Component. Klasserna kan delas in i två grupper Leaf och Composite, klasser utan barn respektive klasser med barn (som också implementerar Component). Oavsett vilken av de två grupperna en klass tillhör, så måste den implementera de operationerna som deklareras i Component på ett meningsfullt sätt. Ofta betyder det att en Component med barn kallar operationen på samtliga sina barn. Ett typiskt exempel är att man vill bygga en hierarki av vy-element. Exemplet i boken bygger på en Component klass: Graphic, och fyra implementerande klasser: Line, Rectangle, Text och Picture. Line, Rectagle och Text är Leaf och Picture är en Composite. Figuren nedan visar klassdiagrammet: 3

Graphic add(graphic) remove(graphic) getchild(integer) Line Rectangle Text Picture add(graphic) remove(graphic) getchild(integer) Figur 4: Ett exempel på vy-element som tillsammans bildar Composite. Tanken är alltså att Picture innehåller (composes) en eller flera Graphics. Implementationen av i Picture kallar draw för alla Graphic-objekt som lagts till med add(graphic). Det går därmed att bygga bilder (Pictures) som innehåller ett godtyckligt antal linjer, rektanglar och texter. Kanske det finaste är att det även går att bygga bilder som innehåller en eller flera andra bilder som innehåller ett godtyckligt antal linjer, rektanglar, texter, och så vidare. Klienten (den delen av koden som använder sig av objekten) vet i regel inget mer än att ett objekt är en Component, eller Graphic i exemplet. Det gör att strukturen enkelt kan utökas till att inkludera fler Component klasser utan att några ändringar behövs i klienten. En implementeringsdetalj som diskuteras i boken är huruvida Graphic ska deklarera metoderna som hanterar eventuella barn. Fördelen med att implementera den koden i Graphic, alltså Component-basklassen, är transparens. Med transparens menas att alla Graphic-objekt, både klasser av Leaf och Composite typ, kan behandlas på samma sätt. Nackdelen är att klienter kan kalla operationer på Leaf som saknar innebörd. Det är inte uppenbart vad add(graphic) innebär för en Line. Man kan låta den inte ha någon effekt alls, men det faktum att en klient kallar add på en Leaf tyder på att något inte står riktigt rätt till, och då kanske det är bättre att signalera det (kasta en Exception). Nackdelen med Composite som tas upp i boken är att det kan göra ens design för generell. Ofta är generellt bra, men låt säga att vi vill begränsa vissa Composite-klasser så att de bara kan innehålla vissa typer av Component. Eftersom alla Composite-klasser implementerar metoder för att hantera barn av valfri Component-typ är det inget som man kan låta kompilatorn sköta. Istället måste sådana kontroller göras vid run-time. Moderna exempel Jag tyckte att det vore intressant att fundera över vilka olika Design Patterns jag stött på i mjukvara som jag själv arbetat med. Boken ger exempel för varje Design Pattern under titeln Known Uses, och ET++ i all ära, men det är här som det faktum att boken kom ut för 15 år sedan märks mest. Nedan följer ett antal riktiga exempel på några av de 23 Design Patterns som listas i boken. Den som går vidare till att läsa boken kan använda listan som komplement till de exempel som redan finns. iphone SDK[1] o Composite Samtliga vy-element ärver från klassen UIView. Bland annat knappar, textfält och bilder ärver från UIView. Man kan lägga till sub-vyer till en UIView med 4

metoden addsubview(uiview), vilket motsvarar add(graphic) från det föregående exemplet. o Chain of Responsiblity Composite, lämpar sig, som boken tar upp, mycket väl till Chain of Responsiblity. Här delegeras ansvar att svara på en interaktion högre upp i hierarkin. Det vill säga om användaren trycker på ett textfält ges textfältet först möjlighet att svara på tryckning innan den skickas uppåt i vy-hierarkin till den UIView som är förälder. Wicket[6] o Composite Component är bas-klassen för alla typer av komponenter som tillsammans utgör en webbsida. Enkla Leaf klasser ärver från WebCompoenent som i sin tur ärver från Component. Composite klasser ärver från MarkupContainer som i sin tur ärver från Component. Här har man alltså valt att inte implementera metoderna som hanterar barn i bas-klassen. o Visitor Hierarkin av komponenter som tillsammans utgör en webbsida kan itereras över genom att kalla visitchildren(visitor) på en MarkupContainer. o Decorator JavaScript strängar som generas av de inbyggda komponenterna för att hantera AJAX kan dekoreras med hjälp av IAjaxCallDecorator. Spring[5] o Singelton En Spring bean är oftast en Singleton (om den inte är en Prototype). o Prototype En Spring bean kan också finnas i flera instanser, då används Prototype för att skapa nya instanser varje gång en särskild bean efterfrågas. o Facade Det finns en mängd exempel på Facade inom Spring-ramverket. Ett exempel är JdbcTemplate som gömmer alla mer eller mindre komplicerade operationer som det innebär att skapa Connection-objekt till en JDBC-databas. Apache Camel[3] o Proxy Bland annat kan man skapa en Proxy för Spring Remoting. Man exporterar då ett Interface till en Proxy-instans på klienten. Klienten kallar metoder på Proxy-objektet ovetandes om att den i bakgrunden kommunicerar via JMS med en server som har den implementerande koden för interfacet. Slutsats Uppsatsen fokuserade konceptet att föredra composition framför arv. En Design Pattern, Composite, som kanske bäst demonstrerar konceptet har gåtts igenom. Förhoppningsvis har det gett läsaren en grundläggande förståelse för varför det i många fall kan vara en fördelaktig design. Jag vet att jag själv gått tillbaka till kod som jag skrivit innan jag läst boken. I flera fall har jag kunna omstrukturera kod som förlitat sig på arv till att använda sig mer av composition. 5

Referenser 1. Amazon.com. http://www.amazon.com/gp/bestsellers/books/280309/ref=pd_zg_hrsr_b_3_4. Senast besökt 2011-12-15. 2. Apple. http://developer.apple.com/devcenter/ios. Senast besökt 2011-12-25. 3. Camel. http://camel.apache.org/tutorial-jmsremoting.html. Senast besökt 2011-12-25. 4. InfoQ. 2007. http://www.infoq.com/news/2007/07/gofcriticism. Senast besökt 2011-12-15. 5. Spring. http://www.springsource.org. Senast besökt 2011-12-25. 6. Wicket. http://wicket.apache.org. Senast besökt 2011-12-25. 6