uml og klasser og objekter i python
DESCRIPTION
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. - PowerPoint PPT PresentationTRANSCRIPT
UML og Klasser og Objekter i Python
Uge 47Computer science, kap 7Martin 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
Entity-relation
Entitet har Egenskab Entitet A står-i-relation-til Entitet B
EgenskabEntitet
Relation
ER-diagram
Et kæledyr har et navn Et kæledyr har en fødselsdag Et kæledyr er ejet af en person
Kæledyr
Navn
Fødselsdag Dødsdag
Ejet af Person
Navn
M
1
ErEn
M
Art1
Navn
Species
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):
makeStart() makeTable(tablecontents)makeEnding()
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
Beggars and philanthropists
Udvikler
check behavior
Correct behaviorBruger
** *
**
*
Check output *
*
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
MinKlasse-attrNummer1-attrNummer2
+metodeNr1+metodeNr2+metodeNr3
Klassenavn
Attributter
Metoder
Access modifiers
Generalisering/specialisering
Klasse A er en underklasse/overklasse af klasse B
+slicing()+()
-length
Sequence
+isAlpha()+isDigit()
String Tuple
+append()+extend()
List
Aggregering/dekomponering
Klasse A er en del af/har delen klasse B
+append()+extend()
List
Object
1*
Organisationer: Århus Universitet
-lønramme-cpr-bankkonto
Ansat
-fagområde
Institut +opretUddannelse()+nedlægUddannelse()+ansæt()+fyr()+opretInstitut()+nedlægInstitut()
-fagområde
Fakultet
Universitet
+underviser()+forsker()
VIP
+administrerer()
TAP
Adjunkt
+lektorbedømmelser()
Lektor
+professorbedømmelser()
Professor
-ansat
*
-arbSted
1
1* 1*
-navn-addresse
Entitet
-ledelse
Organisation
+udnævn()+fjern()
-medlemmer
Ledelse
1 1
-hører under1-udbyder
*
Uddannelse-administreres af*
-udbyder *
Kursus
-tilhører1
-består af*
TAP=Teknisk-Administrativt PersonaleVIP=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)
-lønramme-cpr-bankkonto-er medlem af
Ansat
+udnævn()+fjern()
-medlemmer
Ledelse
-medlem af
*
-har medlem
*
Delvis implementering class Entitet: def __init__(self, navn,addresse): self.navn = navn self.addresse = addresse def verbalize(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
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
def udnaevn(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
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ønramme-cpr-bankkonto
Ansat
+underviser()+forsker()
VIP
+administrerer()
TAP
Adjunkt
+lektorbedømmelser()
Lektor
+professorbedømmelser()
Professor
-titel-ansæt periode
Stilling
* 1
Løs opgaveDiagrammet efter diskussion
Software: OOogSql +makeHTMLTable()
-columnNames-values
SQL
+getPrimaryKey()
-primaryKey-tableName
Persistent
+getRow()-rows
Table
+put()+get()+update()+insert()+delete()
Row
Temporary
1
*
columnNamesvaluesprimaryKeytableName
Object1 : Table
columnNamesvaluesprimaryKeytableName
Object3 : Row
columnNamesvalues
Object2 : Temporary
columnNamesvaluesprimaryKeytableName
Object4 : Persistent
Software: Beggars and philanthropists
Modellering af et simpelt kommunikationssystem for autonome agenter til brug i simuleringer af, hvordan forskellige økonomiske instanser fordeler penge ud frade ansøgninger de modtager, og ligeledes hvordan de forskellige ansøgere udvælger hvorde 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 Logical cohesion: 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
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) Rekursiv definition Samling ::= {Del}* Del ::= Simpel |Samling
Samling
Del Del
Samling
Del Del
+__str__()-navn
Del
+tilfoej()+fjern()+hent()+__str__()
-dele
Samling
Simpel
-helhed
1
-del
*
Nedarvning
Subklassen arver variable og funktioner fra superklassen
Simpel: navn __str__
Samling: navn dele __str__ tilføj fjern hent
Samling overskriver superklassens ’ __str__’
Simpel bevarer superklassens __str__’
Begge arver navn fra overklassen
Samling tilføjer nye ting
+__str__()-navn
Del
+tilfoej()+fjern()+hent()+__str__()
-dele
Samling
Simpel
-helhed
1
-del
*
__init__ og andre funktioner class Del: def __init__(self, navn): self.navn = navn def __str__(self, niveau = 1): text = '\n' + niveau *' '+'(' + self.navn + ')' return text
class Samling(Del): def __init__(self, navn, dele = None): Del.__init__(self, navn)
if dele == None: self.dele = [] else:
self.dele = dele def tilfoej(self,enDel): self.dele.append(enDel) def fjern(self,enDel): if enDel in self.dele: self.dele.remove(enDel) def hent(self,delNavn): for d in self.dele: if d.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 *' '+')' return text
class Simpel(Del): def __init__(self, navn): Del.__init__(self, navn)
superklasse
subklasse
subklasse
initialisering
metoder
Dannelse af objekter
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
Inits parametre
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: 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 def tilfoej(self, enDel): if self.dele == None: self.dele = [] self.dele.append(enDel) def fjern(self,enDel): if self.dele == None: self.dele = [] if enDel in self.dele: self.dele.remove(enDel) def hent(self,delNavn): for d in self.dele: if d.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 *' '+')' return text
metoder der tilhører klassen
Init metoden (Constructor)
klassenavnsuperklasse
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’s init kalder superklassens initHusk at give den parametren self 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__.Simpel instance>, <__main__.Samling instance >,
<__main__.Simpel instance >] >>> bil.stelnummer Traceback (most recent call last): File "<pyshell#7>", line 1, in ? bil.stelnummer AttributeError: Samling instance has no attribute '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 def udskrivSum(self): print self.summer()
etElement = Eksempel([1,2,3,4]) etElement.udskrivSum()
Resultat: 10 >>>
+summer()+udskrivSum()
-minListe
Eksempel
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
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>>>
Er defineret uden for klassens metoder!Derfor ydre scope
Hele Python består af objekter
>>> L = [1,2,3] >>> L.append(4) >>> L [1, 2, 3, 4] >>>
object
+append()+count()+extend()
List
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
+__str__()-navn
Del
+tilfoej()+fjern()+hent()+__str__()
-dele
Samling
Simpel
-helhed
1
-del
*
SQL
Helhedens primærnøgle benyttes som fremmednøgle i delen
Navn HelhedId
hjul 200100
hjul 200101
hjul 200102
NavnId
bil200
bil201
bil202
fremmednøgleDel 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
navndele
Object3 : Samling
navn
Object4 : Del
navn
Object5 : Del
[ , ]
OOogSQL
+init()+makeHTMLTable()+printContents()+combineColumNamesAndValues()+makeVerticalTable()+makeHorizontalTable()
-columnNames-values
SQL
+init()+getPrimaryKey()+printContents()
-primaryKey-tableName-columnNames
Persistent
+init()+getRow()+printContents()
-rows
Table+init()+put()+putAll Values()+get()+update()+insert()+delete()
Row
+init()
Temporary
1 *
Persistent class Persistent(SQL): '''Abstract class''' def __init__(self, tableName, values): self.primaryKey = database.getPrimaryKey(tableName) self.tableName = tableName columnNames = database.getColumnNames(tableName) SQL.__init__(self, columnNames, values) def printContents(self): '''prints the data of the object''' print 'Table name: '+self.tableName print 'Primary key: ' + self.primaryKey SQL.printContents(self) def getPrimaryKey(self): '''returns the primary key''' return self.primaryKey
Genbrug af overklassens funktioner
Overklassens navn
Reference til ’mig selv’Omdefinering af overklassens funktion
Table class Table(Persistent): def __init__(self, tableName): values = database.findRecords(tableName,[]) Persistent.__init__(self,tableName, values) #insert a list of Row-instances corresponding 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 def getRow(self,theKey): '''returns a row-instance whose primary key = theKey if none exists, returns None''' primaryKey = self.getPrimaryKey() for r in self.rows: if r.get(primaryKey) == theKey: return r return None def printContents(self): '''prints the data of the object''' print 'Table name: '+self.tableName print 'Primary key: '+ 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']]
Brug af OOogSQL 2
restore the first name, print a html version of the row aRow.put('firstname','Jeppe Boegh') aRow.update() print aRow.makeHTMLTable()
Resultat <table width="75%" border="1"> <tr> <td>cpr</td> <td>firstname</td> <td>lastname</td> <td>address</td> <td>city</td> <td>gender</td> <td>email</td> <td>phone</td> <td>insurance</td> <td>hasFather</td> <td>hasMother</td> <td>hasDoctor</td> </tr> <tr> <td>1111111111</td> <td>Jeppe Boegh</td> <td>Andersen</td> <td>Thorsgade 20</td> <td>8410</td> <td>dreng</td> <td></td> <td>86379790</td> <td>Baltica</td> <td>1111111112</td> <td>1111111113</td> <td>1111111114</td> </tr> </table>
Brug af OOogSQL 3 make a new empty row-object, insert values into the object
aRow = Row('Child') valueList = ['1111111111', 'Jeppe Boegh', 'Andersen', 'Thorsgade 20',
'8410', 'dreng', '', '86379790', 'Baltica', '1111111112', '1111111113', '1111111114']
aRow.putAllValues(valueList) 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 Boegh', 'Andersen', 'Thorsgade 20', '8410',
'dreng', '', '86379790', 'Baltica', '1111111112', '1111111113', '1111111114']
Brug af OOogSQL 4
create a selection of all children that live at the same address as their mother' SQLordre = '''SELECT Child.cpr, Child.firstname,
Child.lastname FROM Child, Person WHERE Child.hasMother = Person.cpr AND
Child.address = Person.address''' aSelection =
Temporary(['cpr','firstname','lastname'],SQLordre) aSelection.printContents()
Resultat Column names: ['cpr', 'firstname', 'lastname'] Values: (('1111111115', 'Stine', 'Jacobsen '),)
Brug af OOogSQL 5 print aSelection.makeHTMLTable() Resultat <table width="75%" border="1"> <tr> <td>cpr</td> <td>firstname</td> <td>lastname</td> </tr> <tr> <td>1111111115</td> <td>Stine</td> <td>Jacobsen </td> </tr> </table>
Fordelen ved UML
Vi kan beskrive de logiske forhold i problemområdet uden at skulle tage beslutninger om implementeringen At kunne dette er jeres hovedkvalifikation.
Har vi et godt UML diagram er der ikke lang vej til implementering for dygtige programmører.
Databse.py
Ny udgave på nettet, har foretaget nogle ændringer, idet at en session førhen blev lukket efter hvert kald. Dette gav problemer med nogle ting
Husk at lukke connection nu! database.closeConnection() Eller noget der nedarver SQL klassen, ligeledes
objekt.closeConnection()
Opgave 9
Øvelse 9 ligger på hjemmesiden. Udfyld de steder hvor der står ”insert
code here” så det passer til beskrivelsen af metoden eller funktionen
Test at alting virker som det skal