580 likes | 750 Views
UML og Klasser og Objekter i Python. Uge 47 Computer science, kap 7 Martin Fowler: UML distilled , kap. 3. Addision-Wesley , 2004. Learning Python : kap 15-16, 19-22. . Diagrammer. Diagrammer er visuelle fremstillinger af beskrivelser der består af en lang række simple ens sætninger.
E N D
UML og Klasser og Objekter i Python Uge 47 Computer science, kap 7 Martin Fowler: UML distilled, kap. 3. Addision-Wesley, 2004. LearningPython: kap 15-16, 19-22.
Diagrammer • Diagrammer er visuelle fremstillinger af beskrivelser der består af en lang række simple ens sætninger
Entity-relation • Entitet har Egenskab • Entitet A står-i-relation-til Entitet B Relation Entitet Egenskab
ER-diagram • Et kæledyr har et navn • Et kæledyr har en fødselsdag • Et kæledyr er ejet af en person
Kald-struktur • Structure chart • Funktion A kalder funktion B A B
HTML-tabellen • def makeHtmlPage(tablecontents): • return makeStart() + makeTable(tablecontents) + makeEnding() • def makeTable(tablecontents): • …. • htmltabel += makeRow(row) • … • return htmltabel • def makeRow(rowcontents): • …. • htmlrow += makeCell(cell) • …. • return htmlrow
HTML-tabellen makeHtmlPage(tablecontents): makeEnding() makeStart() makeTable(tablecontents) makeRow(rowcontents): makeCell(cell)
Brugsscenarier • Use case diagrams • Defineret ved formål • Aktør interagerer med Systemmodul • Formål her: brugerne og udvikleren retter simuleringen så den passer med brugernes teori • Hvem har hvilke ansvarsområder
UML klassediagrammer • Klasse A er en underklasse/overklasse af klasse B • Klasse A er en del af/har delen klasse B • Klasse A står i relation til klasse B • Klasse A afhænger af klasse B • Klasse A har attributten B • Klasse A kan udføre metoden B
Konventioner for notationsform • Klasser starter altid med stort begyndelsesbogstav og efterfølgende ord ligeledes med stort • Attributter og metoder starter med lille begyndelsesbogstav og efterfølgende ord med stort Klassenavn MinKlasse Attributter Access modifiers -attrNummer1-attrNummer2 +metodeNr1+metodeNr2 +metodeNr3 Metoder
Generalisering/specialisering • Klasse A er en underklasse/overklasse af klasse B
Aggregering/dekomponering • Klasse A er en del af/har delen klasse B
Organisationer: Århus Universitet TAP=Teknisk-AdministrativtPersonaleVIP=Videnskabeligt Personale
Metoder og attributter • Klasse A kan udføre metoden B • Klassen A har attributten B • Primitive attributter defineres i klassen, komplekse bliver defineret som en ny klasse med et tilhørsforhold class Ledelse: def __init__(self, medlemmer, organisation): self.medlemmer = medlemmer self.organisation = organisation def udnaevn(self, medlem): self.medlemmer.append(medlem) def fjern(self, medlem): self.medlemmer.remove(medlem)
Delvis implementering • class Institut(Organisation): • def __init__(self, navn,addresse, ledelse,fagområde): • Organisation.__init__(self, navn,addresse, ledelse) • self.fagområde = fagområde • class Ledelse: • def __init__(self, medlemmer, organisation): • self.medlemmer = medlemmer • self.organisation = organisation • defudnaevn(self, medlem): • self.medlemmer.append(medlem) • def fjern(self, medlem): • self.medlemmer.remove(medlem) • class Ansat(Entitet): • def __init__(self, navn,addresse, lønramme,cpr,bankkonto): • Entitet.__init__(self,navn, addresse) • self.lønramme = lønramme • self.cpr = cpr • self.bankkonto = bankkonto • class Entitet: • def __init__(self, navn,addresse): • self.navn = navn • self.addresse = addresse • defverbalize(self): • print vars(self) • class Organisation(Entitet): • def __init__(self, navn,addresse, ledelse): • Entitet.__init__(self,navn, addresse) • self.ledelse = ledelse • class Uddannelse(Organisation): • def __init__(self, navn,addresse, ledelse, tilknytning): • Organisation.__init__(self, navn,addresse, ledelse) • self.tilknytning=tilknytning • class Universitet(Organisation): • def __init__(self, navn,addresse, ledelse, fakulteter): • Organisation.__init__(self, navn,addresse, ledelse) • self.fakulteter = fakulteter • class Fakultet(Organisation): • def __init__(self, navn,addresse, ledelse, fagområde,institutter,uddannelser): • Organisation.__init__(self, navn,addresse, ledelse) • self.fagområde = fagområde • self.institutter = institutter • self.uddannelser = uddannelser
Implementering • Aggregering: en liste af komponenterne (en beholder) • Specialisering:subklasser • Attributter: variable knyttet til klassen • Metoder: funktioner knyttet til klassen
Patterns • En gennemtestet metode til at løse et bestemt problem (GOF) • State pattern • Løser problemet at en instans ikke kan skifte klasse • Når man bliver lektor skal man oprette en helt ny ansat
Løs opgave Diagrammet efter diskussion
Software: Beggars and philanthropists Modellering af et simpelt kommunikationssystem for autonome agenter til brug i simuleringer af, hvordan forskellige økonomiske instanser fordeler penge ud fra de ansøgninger de modtager, og ligeledes hvordan de forskellige ansøgere udvælger hvor de skal ansøge.
Beggars and philanthropists demo • Prompten viser hvordan de enkelte agenter kommunikerer med hinanden • Hele kildekoden kan ses bagefter hvis der er nogen der har interesse, består af ca. 2600 linjers kode
Kobling • Coupling • Afhængigheder mellem moduler • Kan man rette i eet modul uden at skulle rette i andre moduler? • Skal være lav. • Skal helst kun være i nedadgående retning • Øger genbrugelighed GUI Model Persistens
Sammenhæng • Cohesion • Sammenhæng indenfor det enkelte modul • Logicalcohesion: en klasse repræsenterer en sammenhængende verden. • En person klasse kan ikke have funktioner til at køre en bil. • Skal være høj. • Øger også genbrugelighed, vi kan bruge en rigtigt defineret person klasse mange gang
Engineering og reverse-engineering • Fra diagrammer til kode, kan automatiseres • Fra kode til diagram kan også automatiseres • Diagrammet fra B&P var reverse-engineered
Pause • Pause
Klasser og objekter • En klasse beskriver en klump af samhørende funktioner og variable • En klasse er en beskrivelse. • En kage form • Klassens objekter er instanser af klassen. • De enkelte kager • En programudførelse indeholder (for det meste (klasse reference)) objekter, ikke klasser
Samlingsmønstret (composite) • Behandl helheder og dele på samme måde (her print) • Rekursivdefinition • Samling ::= {Del}* • Del ::= Simpel |Samling Samling Del Del Samling Del Del
Nedarvning • Subklassen arver variable og funktioner fra superklassen • Simpel: • navn • __str__ • Samling: • navn • dele • __str__ • tilføj • fjern • hent Begge arver navn fra overklassen Simpel bevarer superklassens __str__’ Samling tilføjer nye ting Samling overskriver superklassens ’ __str__’
__init__ og andre funktioner • class Del: • def __init__(self, navn): • self.navn = navn • def __str__(self, niveau = 1): • text = '\n' + niveau *' '+'(' + self.navn + ')' • returntext • class Samling(Del): • def __init__(self, navn, dele = None): • Del.__init__(self, navn) if dele == None: self.dele = [] else: • self.dele= dele • deftilfoej(self,enDel): • self.dele.append(enDel) • def fjern(self,enDel): • ifenDel in self.dele: • self.dele.remove(enDel) • def hent(self,delNavn): • for d in self.dele: • ifd.navn == delNavn: • return d • return None • def __str__(self, niveau = 1): • text = '\n' + niveau *' '+'(' + self.navn • for enDel in self.dele: • text += enDel.__str__(niveau+1) • text += '\n' + niveau *' '+')' • returntext • class Simpel(Del): • def __init__(self, navn): • Del.__init__(self, navn) superklasse initialisering subklasse metoder subklasse
Dannelse af objekter Inits parametre • bil = Samling('bil',[Samling('karosseri'),Samling('hjul'),Samling('motor')]) • bil.hent('karosseri').tilfoej(Simpel('Tag')) • bil.hent('karosseri').tilfoej(Simpel('Doere')) • bil.hent('karosseri').tilfoej(Simpel('Bund')) • bil.hent('hjul').tilfoej(Simpel('venstre forhjul')) • bil.hent('hjul').tilfoej(Simpel('venstre forhjul')) • bil.hent('hjul').tilfoej(Simpel('hoejre forhjul')) • bil.hent('hjul').tilfoej(Simpel('venstre baghjul')) • bil.hent('hjul').tilfoej(Simpel('hoejre baghjul')) • bil.hent('motor').tilfoej(Simpel('stempler')) • bil.hent('motor').tilfoej(Simpel('karburator')) • print bil Kald af hjulsamlingens tiltøj-funktion
Output • (bil • (karosseri • (Tag) • (Doere) • (Bund) • ) • (hjul • (venstre forhjul) • (venstre forhjul) • (hoejre forhjul) • (venstre baghjul) • (hoejre baghjul) • ) • (motor • (stempler) • (karburator) • ) • )
Definition af klasser: superklasse • Class <klassenavn>(<evt. superklasse>): • <init-funktionen> • <funktioner der tilhører klassen> • class Samling(Del): • '''repræsenterer en samling af dele, enten samlinger eller simple''' • def __init__(self, navn, dele = None): • Del.__init__(self, navn) • self.dele = dele • deftilfoej(self, enDel): • ifself.dele == None: • self.dele = [] • self.dele.append(enDel) • def fjern(self,enDel): • ifself.dele == None: • self.dele = [] • ifenDel in self.dele: • self.dele.remove(enDel) • def hent(self,delNavn): • for d in self.dele: • ifd.navn == delNavn: • return d • return None • def __str__(self, niveau = 1): • '''giver en textuel repræsentation af klassen • __str__ gør det muligt at printe klassen direkte''' • text = '\n' + niveau *' '+'(' + self.navn • for enDel in self.dele: • text += enDel.__str__(niveau+1) • text += '\n' + niveau *' '+')' • returntext klassenavn Initmetoden (Constructor) metoder der tilhører klassen
Check om det er rigtigt: Introspektion • Python indeholder en række funktioner der giver direkte adgang til dens indvolde • Objekt.__dict__: en dictionary der gemmer objektets attributter og værdier • Dir(object): returnerer alle de attributter og metoder der er knyttet til objektet.
Introspection • def introspect(self): • text = 'Dictionary: ' • text += '\n'+ str(self.__dict__) • text += '\n'+'Attributes and functions: ' • text += '\n'+ str(dir(self)) • return text
Eksempel • Bil (Samling): • Dictionary: • {'dele': [<__main__.Samling instance at 0x00FC2BE8>, <__main__.Samling instance at 0x00FC2CD8>, <__main__.Samling instance at 0x00FC2D00>], • 'navn': 'bil'} • Attributes and Functions : • ['__doc__', '__init__', '__module__', • '__str__', 'dele', 'fjern', 'hent', 'introspect', 'navn', 'tilfoej'] • Tag (Simpel): • Dictionary: • {'navn': 'Tag'} • Attributes and Functions : • ['__doc__', '__init__', '__module__', • '__str__', 'introspect', 'navn'] Nedarvede fra Python Brugerdefinerede
Generering af klasser • Klasse definition • class Simpel(Del): • def __init__(self, navn): • Del.__init__(self, navn) • Generering af klasse • <klassenavn>(<inits parametre undtagen self>) • Forhjul = Simpel('venstre forhjul') • __init__kaldes automatisk når klassen genereres Simpel’sinit kalder superklassens init Husk at give den parametrenself med!!
Self • self henviser til det nydannede objekt • Når man i klassedefinitionen vil henvise til objektets egne funktioner eller variable skal det ske via self • def getName(self): • return self.name
Med og uden self • class Samling(Del): • def __init__(self, navn, dele): • Del.__init__(self, navn) • self.dele = dele • stelnummer = 100 • ’Stelnummer’ er blot en lokal variabel i __init__ der forsvinder når funktionen har kørt. ’Dele’ er derimod fast knyttet til objektet • >>> bil.dele • [<__main__.Simpelinstance>, <__main__.Samlinginstance >, <__main__.Simpelinstance >] • >>> bil.stelnummer • Traceback (most recent call last): • File "<pyshell#7>", line 1, in ? • bil.stelnummer • AttributeError: Samling instance has noattribute 'stelnummer' • >>>
Self bruges også til at referere til objektets egne funktioner • class Eksempel: • def __init__(self,enListe): • self.minListe = enListe • def summer(self): • resultat = 0 • for i in self.minListe: • resultat += i • return resultat • defudskrivSum(self): • print self.summer() • etElement = Eksempel([1,2,3,4]) • etElement.udskrivSum() • Resultat: • 10 • >>>
Udeladelse af self • def udskrivSum(self): • print summer() • Python ved ikke hvad ’summer’ refererer til:’ • print summer() • NameError: global name 'summer' is not defined
Klasse variabler • Det er også muligt at referere direkte til parametre defineret i klassen i stedet for objektet. Dette gøres uden self • Brug af konstante til at gøre koden renere og lettere at omstrukturere, vi bruger A.meters alle steder i stedet for tallet 100, hvis det skulle ændre sig skal vi kun ændre et sted Er defineret uden for klassens metoder!Derfor ydre scope class A: meters = 100 def printer(self): self.meters = 50 print "i objektet: " + str(self.meters)+", i klassen: "+str(A.meters) print "i klassen: "+ str(A.meters) instance = A() instance.printer() >>> >>>i klassen: 100 >>>i objektet: 50, i klassen: 100 >>>
Hele Python består af objekter • >>> L = [1,2,3] • >>> L.append(4) • >>> L • [1, 2, 3, 4] • >>>
Relationer mellem objekter • Der er en én-mange relation mellem en samling og dens dele • En relation er et abstrakt begreb der kan implementeres på mange måder. • SQL: som en relation • Python: som en liste af objekter
SQL • Helhedens primærnøgle benyttes som fremmednøgle i delen Del Samling
Python • class Samling(Del): • def __init__(self, navn, dele): • Del.__init__(self, navn) • self.dele = dele • Helheden har en liste over de objekter der repræsenterer dens dele
Persistent Omdefinering af overklassens funktion Reference til ’mig selv’ • classPersistent(SQL): • '''Abstractclass''' • def __init__(self, tableName, values): • self.primaryKey = database.getPrimaryKey(tableName) • self.tableName = tableName • columnNames = database.getColumnNames(tableName) • SQL.__init__(self, columnNames, values) • defprintContents(self): • '''prints the data of the object''' • print 'Tablename: '+self.tableName • print 'Primarykey: ' + self.primaryKey • SQL.printContents(self) • defgetPrimaryKey(self): • '''returns the primarykey''' • returnself.primaryKey Overklassens navn Genbrug afoverklassensfunktioner
Table • classTable(Persistent): • def __init__(self, tableName): • values = database.findRecords(tableName,[]) • Persistent.__init__(self,tableName, values) • #insert a list of Row-instancescorresponding to the values • rows =[] • primaryKey = self.getPrimaryKey() • i = self.columnNames.index(primaryKey) • for v in self.values: • theKey = v[i] • rows.append(Row(tableName,theKey)) • self.rows = rows • defgetRow(self,theKey): • '''returns a row-instancewhoseprimarykey = theKey • if none exists, returns None''' • primaryKey = self.getPrimaryKey() • for r in self.rows: • ifr.get(primaryKey) == theKey: • return r • return None • defprintContents(self): • '''prints the data of the object''' • print 'Tablename: '+self.tableName • print 'Primarykey: '+ self.primaryKey • print ’Column names: \n' + str(self.columnNames) • print 'Components: ' • for c in self.rows: • c.printContents() Self.getPrimaryKey() er nedarvet fra overklassen
Brug af OOogSQL 1 • fetch a row from Child with primary key 1111111111, change the first name to Jeppe and store it, fetch the row again to see if the change worked • aRow = Row('Child','1111111111') • aRow.put('firstname','Jeppe') • aRow.update() • aRow = Row('Child','1111111111') • aRow.printContents() • Resultat: • Table name: Child • Primary key: cpr • Column names: ['cpr', 'firstname', 'lastname', 'address', 'city', 'gender', 'email', 'phone', 'insurance', 'hasFather', 'hasMother', 'hasDoctor'] • Values: [['1111111111', 'Jeppe', 'Andersen', 'Thorsgade 20', '8410', 'dreng', '', '86379790', 'Baltica', '1111111112', '1111111113', '1111111114']]