Poglavlje 6: Strukturni model – klase i objekti

Priča za početak. Početkom šezdesetih godina dvojica norveških naučnika, Ole-Johan Dahl i Kristen Nygaard, radili su u Norveškom računskom centru u Oslu na simulacijama: kako se ponaša red brodova u luci, kako teče posao u fabrici, gdje se stvaraju gužve. Programi tog vremena bili su dugi spiskovi naredbi, i u njima se teško vidjelo šta je brod, a šta dizalica. Dahl i Nygaard su smislili drugačiji način: program se sastoji od objekata koji liče na stvari iz stvarnog svijeta, a svaki objekat ima svoje podatke i svoje ponašanje. Opis po kojem se prave svi brodovi iste vrste nazvali su klasa. Jezik koji su napravili zvao se Simula, a njegova verzija iz 1967. godine prvi je jezik s klasama, objektima i nasljeđivanjem. Kasnije su iz te ideje nastali Smalltalk, C++, Java, Python i C#, pa danas skoro svaki programer misli u objektima. Dahl i Nygaard su 2001. godine dobili Turingovu nagradu, koja se često naziva „Nobelovom nagradom za računarstvo”, upravo za objektno orijentisano programiranje.

U poglavlju 5 opisali smo šta DeliveryApp radi za svakog aktera. Sada pitamo: šta DeliveryApp zna? Koje „stvari” postoje u sistemu, šta o svakoj pamti i kako su povezane? Odgovor daje strukturni model, a u UML-u ga crtamo dijagramom klasa. Prvo objašnjavamo objekat i klasu, uz Python kod. Zatim učimo veze među klasama: asocijaciju, višestrukost, kompoziciju i nasljeđivanje. Na kraju iz teksta vizije pronalazimo klase i crtamo domenski model DeliveryApp. Na praktičnoj nastavi isti model crtamo u Mermaidu i pišemo ga kao Python klase koje računaju 24,50 €.

Literatura. Osnovna literatura predmeta:

  1. B. Popović, K. Kuk: Informacioni sistemi, Kriminalističko-policijski univerzitet, Beograd, 2017.
  2. J. S. Valacich, J. F. George: Modern Systems Analysis and Design, 9th ed., Pearson, 2020.
  3. L. Jelenković: Sustavi za rad u stvarnom vremenu – skripta, FER, Zagreb, 2015.
  4. D. Milićev: Programiranje u realnom vremenu – skripta, Beograd, 2002.
  5. V. Kovačević, M. Popović: Sistemska programska podrška u realnom vremenu 1, FTN, Novi Sad, 2013.

Riječi ovog poglavlja.

  • Objekat – jedna konkretna stvar u sistemu, s vlastitim podacima (npr. narudžba N-1001).
  • Klasa – opis po kojem se prave svi objekti iste vrste (npr. klasa Narudžba).
  • Atribut – podatak koji objekat pamti (broj, stanje, udaljenost).
  • Operacija (metoda) – nešto što objekat zna uraditi (dodati stavku, izračunati ukupno).
  • Instanca – drugo ime za objekat napravljen po klasi.
  • Enkapsulacija – skrivanje unutrašnjih podataka objekta, tako da se mijenjaju samo kroz njegove operacije.
  • Asocijacija – veza između klasa koja kaže da se njihovi objekti „poznaju” (kupac pravi narudžbu).
  • Višestrukost – koliko objekata jedne klase može biti povezano s jednim objektom druge (1, 0..1, 0.., 1..).
  • Kompozicija – jaka veza „dio–cjelina”: dio ne postoji bez cjeline (stavka bez narudžbe).
  • Agregacija – slaba veza „dio–cjelina”: dio postoji i sam (dostavljač bez tima).
  • Nasljeđivanje (generalizacija) – posebna klasa preuzima sve od opšte i dodaje svoje (Kupac je vrsta Korisnika).
  • Domenski model – dijagram klasa koji opisuje pojmove posla, bez tehničkih detalja.
  • Dijagram objekata – slika stvarnih objekata i njihovih vrijednosti u jednom trenutku.

Ciljevi poglavlja. Nakon poglavlja možete: objasniti razliku između objekta i klase na primjeru narudžbe; za objekat navesti stanje, ponašanje i identitet; nacrtati klasu u UML-u s atributima, tipovima, operacijama i vidljivošću; objasniti enkapsulaciju i zašto stanje narudžbe ne mijenjamo direktno; nacrtati asocijaciju s višestrukošću i pročitati je kao rečenicu; razlikovati kompoziciju, agregaciju i običnu asocijaciju; prepoznati kada je nasljeđivanje dobar izbor, a kada nije; iz teksta vizije izdvojiti kandidate za klase, atribute i operacije; nacrtati domenski model DeliveryApp u Mermaidu; napisati kostur klasa u Pythonu i provjeriti da daje 24,50 € za N-1001; nacrtati dijagram objekata za N-1001.

Plan poglavlja – Sedmica 6: tri časa teorije i tri časa praktične nastave

Čas Sadržaj Na času
Teorija 1 6.1–6.3 Objekat, klasa, enkapsulacija Kalup i kolači; klasa Narudžba u UML-u i Pythonu
Teorija 2 6.4–6.6 Asocijacija, višestrukost, kompozicija, nasljeđivanje „Jedan kupac pravi nula ili više narudžbi”
Teorija 3 6.7–6.9 Od imenica do klasa; domenski model; objekti Domenski model DeliveryApp; N-1001 kao objekti
Praksa 1–3 Mermaid classDiagram; Python klase model.py računa 24,50 €

Dio 1 – Objekat i klasa

6.1 Objekat

Objekat je jedna konkretna stvar u sistemu. Narudžba N-1001 je objekat. Picerija R-1 je objekat. Pizza Margarita na jelovniku R-1 je objekat. Svaki objekat ima tri osobine:

  1. Stanje – podaci koje objekat u ovom trenutku pamti. Narudžba N-1001 pamti: broj „N-1001”, kupca K-01, restoran R-1, udaljenost 4,2 km, dvije stavke i stanje NOVA.
  2. Ponašanje – šta objekat zna uraditi. Narudžba zna dodati stavku, izračunati ukupnu cijenu i promijeniti stanje.
  3. Identitet – po čemu je ovaj objekat on, a ne neki drugi. Dvije narudžbe mogu imati iste stavke i istu adresu, ali su ipak dvije različite narudžbe (N-1001 i N-1007), kao što dvije sestre bliznakinje nisu ista osoba.

Objekat može predstavljati i nešto što se ne može dodirnuti: narudžbu, plaćanje, kod popusta. Pravilo je jednostavno: ako sistem o nečemu mora pamtiti podatke i to nešto treba razlikovati od drugih iste vrste, to je kandidat za objekat.

Ukratko.

  • Objekat je jedna konkretna stvar u sistemu, opipljiva ili ne (narudžba, restoran, plaćanje).
  • Objekat ima stanje (podatke), ponašanje (šta zna uraditi) i identitet (po čemu je baš on).
  • Ako sistem o nečemu pamti podatke i razlikuje ga od drugih, to je kandidat za objekat.

6.2 Klasa

Klasa je opis po kojem se prave svi objekti iste vrste. Klasa Narudžba kaže: svaka narudžba ima broj, kupca, restoran, udaljenost, stavke i stanje, i svaka zna izračunati ukupnu cijenu. Svaki pojedinačni objekat (N-1001, N-1002…) je instanca te klase: ima istu građu, ali svoje vrijednosti.

Najbolja slika iz života je kalup za kolače. Kalup je klasa: određuje oblik. Kolači su objekti: svaki ima isti oblik, ali jedan je s čokoladom, drugi s vanilom, a treći je pojeden. Kalup se ne jede; kolač se jede. Isto tako, klasa Narudžba ne košta ništa; narudžba N-1001 košta 24,50 €.

Klasa u UML-u

U dijagramu klasa klasa se crta kao pravougaonik s tri dijela:

  1. gore ime klase (imenica u jednini, veliko početno slovo: Narudzba);
  2. u sredini atributi, u obliku ime: tip;
  3. dolje operacije, u obliku ime(parametri): tip rezultata.

Ispred atributa i operacija stoji znak vidljivosti: + znači javno (svi smiju koristiti), - znači privatno (samo sam objekat), # znači zaštićeno (objekat i njegove podklase). Evo klase Narudzba kao Mermaid teksta:

classDiagram
    class Narudzba {
        +broj: str
        +udaljenost_km: float
        -stanje: str
        +dodaj(jelo: Jelo, kolicina: int)
        +artikli() int
        +dostava() int
        +ukupno() int
        +promijeni(novo: str)
    }

Primijetite da u imenima pišemo „Narudzba” bez slova ž. Mermaid i većina programskih jezika dozvoljavaju i naša slova, ali mnogi alati i baze s njima imaju problema, pa je dobra navika da se u imenima u kodu koriste samo engleska slova, a u tekstu za ljude puni dijakritici.

Ista klasa u Pythonu

Dijagram i kod opisuju isto. Ovako izgleda dio klase u Pythonu (cijeli fajl je primjeri/deliveryapp/model.py):

@dataclass
class Narudzba:
    broj: str
    kupac: Kupac
    restoran: Restoran
    udaljenost_km: float
    kod: str | None = None
    stavke: list = field(default_factory=list)
    stanje: str = "NOVA"

    def dodaj(self, jelo, kolicina=1):
        self.stavke.append(Stavka(jelo, kolicina))

    def artikli(self):
        return sum(s.iznos() for s in self.stavke)

    def ukupno(self):
        a = self.artikli()
        return a - popust(a, self.kod) + self.dostava()

Oznaka @dataclass kaže Pythonu da sam napravi dio koda koji puni atribute; mi pišemo samo atribute i operacije. Iznosi su u centima (950 znači 9,50 €), da bi se izbjegle greške zaokruživanja decimalnih brojeva u računaru; na ekranu ih pretvaramo nazad u eure.

Slika 6.1 – Klasa je kalup, objekti su kolači: klasa Narudzba i tri njene instance

Ukratko.

  • Klasa je opis po kojem se prave objekti iste vrste, kao kalup za kolače.
  • Svaki objekat je instanca klase: ista građa, svoje vrijednosti.
  • U UML-u klasa je pravougaonik s imenom, atributima i operacijama; + je javno, − privatno.
  • Isti model se piše i kao Python klasa; iznosi su u centima da se izbjegne zaokruživanje.

6.3 Enkapsulacija

Zamislite da svako ko ima pristup narudžbi može direktno napisati n.stanje = "OTKAZANA", u bilo kom trenutku. Šta sprečava da neko otkaže narudžbu koja je već na putu, suprotno pravilu PP-6? Ništa.

Enkapsulacija (od latinskog „u kapsulu”) znači da objekat skriva svoje unutrašnje podatke, a mijenja ih samo kroz svoje operacije, koje provjeravaju pravila. Narudžba ne dozvoljava da joj neko spolja postavi stanje; dozvoljava samo poziv promijeni("OTKAZANA"), a ta operacija prvo provjeri je li prelaz dozvoljen:

def promijeni(self, novo):
    if novo not in PRELAZI[self.stanje]:
        raise ValueError(f"nedozvoljen prelaz {self.stanje} -> {novo}")
    self.stanje = novo

Zato je u UML-u atribut stanje označen s - (privatno), a operacija promijeni s + (javno).

Slika iz života: bankomat. Novac je u kapsuli; ne možete otvoriti bankomat i uzeti koliko hoćete. Možete samo pozvati operaciju „podigni 50 €”, a bankomat provjeri PIN i stanje računa prije nego što isplati. Pravila su na jednom mjestu, unutar objekta, i niko ih ne može zaobići.

Česta zabluda. „Enkapsulacija je skrivanje od drugih programera, iz nepovjerenja.” Nije. Enkapsulacija čuva pravila na jednom mjestu. Kad se pravilo PP-6 promijeni, mijenja se samo operacija promijeni, a ne stotinu mjesta u kodu koja su direktno pisala stanje.

Ukratko.

  • Enkapsulacija znači da objekat skriva svoje podatke i mijenja ih samo kroz operacije koje provjeravaju pravila.
  • Stanje narudžbe je privatno; mijenja se samo operacijom promijeni(), koja provjerava PP-6.
  • Kao bankomat: novac je u kapsuli, a isplata ide samo kroz operaciju s provjerom.

Provjeri se.

  1. Koje tri osobine ima svaki objekat? – Stanje, ponašanje i identitet.
  2. Šta je razlika između klase i objekta? – Klasa je opis (kalup), a objekat je konkretna instanca s vrijednostima (kolač).
  3. Zašto je atribut stanje privatan? – Da bi se mijenjao samo kroz operaciju koja provjerava dozvoljene prelaze.

Dio 2 – Veze između klasa

6.4 Asocijacija i višestrukost

Klase same nisu mnogo korisne. Narudžba mora znati čija je i iz kojeg restorana. Veza koja kaže da se objekti dvije klase „poznaju” zove se asocijacija i crta se linijom između klasa. Na krajevima linije piše višestrukost: koliko objekata s te strane može biti povezano s jednim objektom s druge strane.

Oznaka Značenje Primjer
1 tačno jedan narudžba ima tačno jednog kupca
0..1 nijedan ili jedan narudžba ima nijednog ili jednog dostavljača (dok ga ne dobije)
0..* ili * nijedan ili više kupac može imati nula ili više narudžbi
1..* jedan ili više narudžba ima bar jednu stavku

Asocijacija se čita kao rečenica, u oba smjera. Za vezu Kupac "1" --> "0..*" Narudzba : pravi:

  • „Jedan kupac pravi nula ili više narudžbi.”
  • „Jedna narudžba pripada tačno jednom kupcu.”

Ako se rečenica ne slaže sa stvarnošću, dijagram je pogrešan. Može li narudžba imati dva kupca? U DeliveryApp ne. Može li kupac postojati bez ijedne narudžbe? Da, tek se registrovao. Zato je višestrukost na strani narudžbe 0..*, a ne 1..*.

Višestrukost nije sitnica. Ona direktno postaje pravilo u bazi (poglavlje 8) i provjera u kodu. Ako je na strani stavki 1..*, sistem ne smije sačuvati narudžbu bez ijedne stavke.

Na času. Pročitajte naglas, u oba smjera: Narudzba "0..*" --> "0..1" Dostavljac : nosi. Zašto je na strani dostavljača 0..1, a ne 1? (Jer narudžba u stanju NOVA još nema dostavljača.)

Ukratko.

  • Asocijacija je linija koja kaže da se objekti dvije klase poznaju.
  • Višestrukost na krajevima linije kaže koliko objekata može biti povezano: 1, 0..1, 0..* ili 1..*.
  • Asocijacija se čita kao rečenica u oba smjera, i mora se slagati sa stvarnošću.
  • Višestrukost postaje pravilo u bazi i provjera u kodu.

6.5 Kompozicija i agregacija

Neke asocijacije su posebne: jedna strana je cjelina, a druga njen dio. UML razlikuje dvije jačine te veze.

Kompozicija je jaka veza: dio ne postoji bez cjeline i nestaje zajedno s njom. Crta se punim rombom (◆) na strani cjeline. Stavka „2 × Pizza Margarita” nema smisla bez narudžbe N-1001: ako se narudžba obriše, briše se i stavka. Isto važi za jelo na jelovniku restorana u DeliveryApp: kad restoran napusti DeliveryApp, njegov jelovnik nestaje s njim.

Agregacija je slaba veza: dio postoji i sam, a cjelina ga samo okuplja. Crta se praznim rombom (◇). Dostavljač D-2 može biti u timu „Jutarnja smjena”, ali ako se tim raspusti, D-2 i dalje postoji i vozi.

Slika iz života: kuća i sobe su kompozicija; kad se kuća sruši, sobe nestaju s njom. Fudbalski tim i igrači su agregacija; kad se tim raspusti, igrači prelaze u druge timove.

U praksi se agregacija rijetko crta, jer se teško razlikuje od obične asocijacije. Kompozicija je korisnija, jer kaže nešto važno za bazu i kod: brisanje cjeline briše i dijelove.

Ukratko.

  • Kompozicija (pun romb) je jaka veza: dio ne postoji bez cjeline, kao stavka bez narudžbe.
  • Agregacija (prazan romb) je slaba veza: dio postoji i sam, kao dostavljač bez tima.
  • Kompozicija kaže da brisanje cjeline briše i njene dijelove.

6.6 Nasljeđivanje

Kupac, dostavljač i osoblje restorana imaju mnogo zajedničkog: svi se prijavljuju, svi imaju ime, e-mail i lozinku. Umjesto da ista tri atributa pišemo tri puta, napravimo opštu klasu Korisnik, a posebne klase je nasljeđuju: preuzimaju sve od nje i dodaju svoje. Kupac dodaje adrese, Dostavljac dodaje vrstu vozila.

U UML-u se nasljeđivanje (generalizacija) crta punom linijom sa šupljim trouglom na strani opšte klase. Čita se „je vrsta”: kupac je vrsta korisnika.

classDiagram
    Korisnik <|-- Kupac
    Korisnik <|-- Dostavljac
    Korisnik <|-- OsobljeRestorana
    class Korisnik {
        +email: str
        -lozinka_hes: str
        +prijavi(email, lozinka) bool
    }
    class Kupac {
        +adrese: list
    }
    class Dostavljac {
        +vozilo: str
    }

Kada nasljeđivanje nije dobar izbor

Nasljeđivanje je moćno, ali se lako zloupotrebi. Dva testa:

  1. Test „je vrsta”. Ako rečenica „B je vrsta A” zvuči čudno, nasljeđivanje je pogrešno. „Stavka je vrsta narudžbe”? Ne; stavka je dio narudžbe, pa je to kompozicija.
  2. Test zamjene. Svuda gdje sistem očekuje opštu klasu mora moći raditi i posebna, bez iznenađenja. Ako bi PlacanjeGotovinom moralo baciti grešku na operaciju „vrati novac na karticu”, onda možda ne treba nasljeđivati PlacanjeKarticom, nego obje klase trebaju nasljeđivati opštije Placanje.

U savremenom projektovanju često se kaže: radije sastavljaj nego nasljeđuj (composition over inheritance). Ako kupac i dostavljač samo dijele adresu, bolje je da oba imaju objekat Adresa nego da nasljeđuju klasu koja „ima adresu”.

Slika 6.2 – Četiri vrste veza: asocijacija, kompozicija, agregacija i nasljeđivanje

Ukratko.

  • Nasljeđivanje znači da posebna klasa preuzima sve od opšte i dodaje svoje; crta se šupljim trouglom.
  • Nasljeđivanje se čita „je vrsta”: kupac je vrsta korisnika.
  • Ako „je vrsta” zvuči čudno, ili posebna klasa ne može zamijeniti opštu, nasljeđivanje je pogrešno.
  • Često je bolje sastavljati objekte (kupac ima adresu) nego nasljeđivati.

Provjeri se.

  1. Pročitajte vezu Narudzba "1" *-- "1..*" Stavka. – Jedna narudžba se sastoji od jedne ili više stavki, a stavka ne postoji bez svoje narudžbe.
  2. Koja je razlika između kompozicije i agregacije? – Kod kompozicije dio ne postoji bez cjeline, a kod agregacije postoji i sam.
  3. Da li je Stavka vrsta Narudžbe? – Ne; stavka je dio narudžbe, pa je veza kompozicija, a ne nasljeđivanje.

Dio 3 – Domenski model DeliveryApp

6.7 Od imenica do klasa

Odakle znamo koje klase DeliveryApp treba? Najjednostavnija tehnika je analiza teksta: uzmemo viziju, korisničke priče i specifikacije slučajeva korištenja i podvučemo imenice i glagole.

  • Imenice su kandidati za klase ili atribute.
  • Glagoli su kandidati za operacije ili asocijacije.

Iz specifikacije UC-01 (poglavlje 5): „Kupac bira jela i količine; sistem pokazuje zbir artikala. Kupac unosi adresu dostave. Sistem traži udaljenost od servisa mapa… Sistem pravi narudžbu u stanju NOVA i prikazuje je restoranu.”

Kandidate zatim sortiramo:

Imenica Odluka Zašto
Kupac klasa sistem pamti njegove podatke i razlikuje kupce
Jelo klasa ima naziv i cijenu; restoran ih ima više
Količina atribut (stavke) broj, nema svoje ponašanje
Zbir artikala operacija računa se iz stavki, ne pamti se
Adresa klasa ili atribut klasa, ako kupac ima više adresa; inače atribut
Udaljenost atribut (narudžbe) broj u km
Servis mapa nije klasa domena vanjski sistem (akter), ne pojam posla
Sistem odbaciti to je DeliveryApp sam
Narudžba klasa srce sistema
Stanje atribut jedna od sedam vrijednosti
Restoran klasa ima jelovnik i narudžbe

Primijetite tri pravila: ono što se računa nije atribut (zbir artikala računamo, ne pamtimo, jer bi inače mogao biti netačan); vanjski sistemi nisu klase domena; i „sistem” se odbacuje.

Ukratko.

  • Analiza teksta: imenice su kandidati za klase ili atribute, glagoli za operacije ili veze.
  • Kandidati se sortiraju: šta se pamti i razlikuje je klasa; jednostavan broj je atribut; ono što se računa je operacija.
  • Vanjski sistemi i riječ „sistem” nisu klase domena.

6.8 Domenski model

Domenski model je dijagram klasa koji opisuje pojmove posla i njihove veze, bez tehničkih detalja (nema baze, ekrana, servera). Razumije ga i vlasnik restorana: on će reći „narudžba uvijek ima bar jedno jelo”, a mi ćemo to pročitati kao višestrukost 1..*.

Domenski model DeliveryApp:

classDiagram
    class Kupac {
        +oznaka: str
        +telefon: str
    }
    class Adresa {
        +ulica: str
        +broj: str
    }
    class Restoran {
        +oznaka: str
        +naziv: str
        +otvoren: bool
    }
    class Jelo {
        +naziv: str
        +cijena: int
        +dostupno: bool
    }
    class Narudzba {
        +broj: str
        +udaljenost_km: float
        -stanje: str
        +artikli() int
        +dostava() int
        +ukupno() int
        +promijeni(novo)
    }
    class Stavka {
        +kolicina: int
        +iznos() int
    }
    class Dostavljac {
        +oznaka: str
        +vozilo: str
    }
    class Placanje {
        +iznos: int
        +odobreno: bool
    }
    class KodPopusta {
        +kod: str
        +procenat: int
        +max_iznos: int
    }
    Kupac "1" --> "1..*" Adresa : ima
    Kupac "1" --> "0..*" Narudzba : pravi
    Restoran "1" *-- "1..*" Jelo : nudi
    Narudzba "0..*" --> "1" Restoran : iz
    Narudzba "1" *-- "1..*" Stavka : sadrži
    Stavka "0..*" --> "1" Jelo : od
    Narudzba "0..*" --> "0..1" Dostavljac : nosi
    Narudzba "1" --> "0..1" Placanje : plaćena
    Narudzba "0..*" --> "0..1" KodPopusta : koristi

Pročitajmo nekoliko veza kao rečenice: „Jedan restoran nudi jedno ili više jela, a jelo ne postoji bez restorana.” „Jedna narudžba sadrži jednu ili više stavki.” „Svaka stavka je od tačno jednog jela, a jedno jelo može biti u mnogo stavki.” „Narudžba može koristiti nijedan ili jedan kod popusta.”

Jedno pitanje vrijedi postaviti glasno: zašto Stavka ima samo količinu, a ne i cijenu? Ako restoran sutra poskupi Margaritu na 10,00 €, da li se mijenja i cijena već plaćene narudžbe N-1001? Ne smije! Zato u stvarnom sistemu stavka pamti cijenu u trenutku narudžbe (cijena_u_trenutku: int). Ovo je primjer kako domenski model otkriva poslovno pravilo koje niko nije izgovorio. Dopisujemo ga u backlog i u model.

Slika 6.3 – Domenski model DeliveryApp

Ukratko.

  • Domenski model je dijagram klasa s pojmovima posla, bez tehničkih detalja.
  • DeliveryApp ima devet klasa: Kupac, Adresa, Restoran, Jelo, Narudžba, Stavka, Dostavljač, Plaćanje i KodPopusta.
  • Svaka veza se čita kao rečenica koju potvrđuje čovjek iz posla.
  • Model je otkrio novo pravilo: stavka pamti cijenu u trenutku narudžbe.

6.9 Dijagram objekata

Dijagram klasa je kalup. Ponekad je korisno nacrtati i kolače: stvarne objekte s vrijednostima u jednom trenutku. To je dijagram objekata. Ime objekta piše se podvučeno, u obliku ime: Klasa, a umjesto tipova stoje vrijednosti.

Narudžba N-1001, u trenutku kad je plaćena:

Objekat Vrijednosti
k01: Kupac oznaka = “K-01”
r1: Restoran oznaka = “R-1”, naziv = “Picerija”
margarita: Jelo naziv = “Pizza Margarita”, cijena = 950
sok: Jelo naziv = “Sok”, cijena = 250
n1001: Narudzba broj = “N-1001”, udaljenost_km = 4.2, stanje = “NOVA”
s1: Stavka kolicina = 2 → margarita
s2: Stavka kolicina = 1 → sok

Iz ovih vrijednosti operacije daju: s1.iznos() = 2 × 950 = 1900; s2.iznos() = 250; n1001.artikli() = 2150; n1001.dostava() = 300; n1001.ukupno() = 2450 centi = 24,50 €.

Dijagram objekata je odličan za provjeru modela: ako ne možete nacrtati stvaran primjer s vrijednostima, model ima rupu. Probajte, na primjer, nacrtati narudžbu bez stavki: višestrukost 1..* kaže da to nije dozvoljeno, i dijagram objekata to odmah pokaže.

Slika 6.4 – Dijagram objekata: narudžba N-1001 u trenutku plaćanja

Ukratko.

  • Dijagram objekata prikazuje stvarne objekte i njihove vrijednosti u jednom trenutku.
  • Za N-1001 operacije daju 2150 centi artikala, 300 centi dostave i ukupno 2450 centi, odnosno 24,50 €.
  • Ako se ne može nacrtati stvaran primjer s vrijednostima, model ima rupu.

Provjeri se.

  1. Zašto „zbir artikala” nije atribut? – Jer se računa iz stavki; da se pamti, mogao bi postati netačan.
  2. Zašto Servis mapa nije klasa domenskog modela? – To je vanjski sistem (akter), a ne pojam posla.
  3. Koliko je n1001.ukupno()? – 2450 centi, odnosno 24,50 €.

Praktična nastava – domenski model u Mermaidu i Pythonu

Cilj je nacrtati domenski model DeliveryApp i napisati ga kao Python klase koje računaju cijenu narudžbe po pravilima PP-1 do PP-5. Fajlovi idu u modeli/ i kod/ repozitorija deliveryapp-projekat.

Korak 1 – Analiza teksta

U modeli/klase.md napravite tabelu imenica iz svoje specifikacije UC-01 i UC-02 (poglavlje 5) s odlukom: klasa, atribut, operacija ili odbaciti, i razlogom. Najmanje 15 imenica.

Korak 2 – Domenski model u Mermaidu

  1. U modeli/klase.md prepišite domenski model iz 6.8 (blok mermaid).
  2. Dodajte atribut cijena_u_trenutku: int u klasu Stavka.
  3. Dodajte klasu Ocjena (kupac ocjenjuje restoran od 1 do 5 nakon isporuke) s vezama i višestrukošću. Napišite obje rečenice za svaku novu vezu.
  4. Dodajte nasljeđivanje Korisnik → Kupac, Dostavljac, OsobljeRestorana iz 6.6.
  5. Provjerite da se dijagram iscrtava (pregled u VS Codeu ili mermaid.live).

Korak 3 – Python klase

  1. U folder kod/ kopirajte deliveryapp.py i model.py iz primjeri/deliveryapp/ (repozitorij udžbenika) ili ih prepišite.
  2. Pokrenite u terminalu:
python model.py

Očekivani ispis:

N-1001 artikli 21,50 € dostava 3,00 € ukupno 24,50 €
sa kodom 22,35 €
  1. Dodajte u klasu Narudzba operaciju promijeni(novo) iz 6.3, koja koristi rječnik PRELAZI iz deliveryapp.py.
  2. Na kraj model.py dodajte provjere:
n.promijeni("PRIHVAĆENA")
n.promijeni("U_PRIPREMI")
try:
    n.promijeni("OTKAZANA")
    print("GREŠKA: otkazivanje u pripremi je prošlo")
except ValueError:
    print("ispravno: otkazivanje u pripremi nije dozvoljeno (PP-6)")
  1. Napravite i narudžbu N-1002 (4 × Ćevapi, 2,5 km) i provjerite da je ukupno 3200 centi.

Korak 4 – Dijagram objekata

Nacrtajte (u Mermaidu kao classDiagram s imenima objekata, ili na papiru pa slikajte) dijagram objekata za N-1002 u trenutku isporuke: kupac, restoran, jelo, stavka, narudžba, dostavljač D-3 i plaćanje.

Korak 5 – AI kao recenzent modela (opcionalno)

Dajte AI asistentu svoj Mermaid domenski model i zatražite: „Pročitaj svaku vezu kao rečenicu u oba smjera i reci mi koja ti zvuči sumnjivo za aplikaciju za dostavu hrane.” Za svaku primjedbu odlučite sami da li je opravdana. Zatražite i da iz modela napiše Python klase; pokrenite ih i uporedite rezultat s 24,50 €.

Rezultat koji se predaje: modeli/klase.md (analiza teksta i domenski model s dodacima), kod/model.py koji ispisuje 24,50 €, 22,35 €, poruku o PP-6 i 32,00 € za N-1002, te dijagram objekata za N-1002.

Vježbe

Vježba za studenta 1 – objekat ili klasa.

Šta je klasa, a šta objekat? a) Pizza Margarita na jelovniku R-1; b) Jelo; c) dostavljač D-3; d) Plaćanje; e) plaćanje karticom za N-1001 u iznosu 24,50 €.

Rješenje. Klase: b) Jelo, d) Plaćanje. Objekti: a) (instanca klase Jelo), c) (instanca klase Dostavljač), e) (instanca klase Plaćanje).

Vježba za studenta 2 – višestrukost.

Napišite višestrukost i pročitajte vezu u oba smjera: a) Restoran – Narudžba; b) Kupac – Adresa (kupac mora imati bar jednu adresu da bi naručio, a može ih sačuvati više); c) Narudžba – Plaćanje.

Rješenje. a) Restoran "1" <-- "0..*" Narudzba: jedan restoran ima nula ili više narudžbi; jedna narudžba je iz tačno jednog restorana. b) Kupac "1" --> "1..*" Adresa: jedan kupac ima jednu ili više adresa; jedna adresa pripada jednom kupcu. c) Narudzba "1" --> "0..1" Placanje: jedna narudžba ima nijedno ili jedno plaćanje (prije naplate nijedno); plaćanje pripada tačno jednoj narudžbi.

Vježba za studenta 3 – kompozicija, agregacija ili nasljeđivanje.

  1. Restoran i Jelo; b) Tim dostavljača i Dostavljač; c) PlacanjeKarticom i Placanje; d) Narudžba i Kupac.

Rješenje. a) kompozicija (jelo u DeliveryApp ne postoji bez restorana); b) agregacija (dostavljač postoji i bez tima); c) nasljeđivanje (plaćanje karticom je vrsta plaćanja); d) obična asocijacija (kupac nije dio narudžbe, niti obrnuto).

Vježba za studenta 4 – računanje kroz objekte.

Napravite (na papiru) objekte za narudžbu N-1005: kupac K-05 iz Salatarnice R-3 naručuje 2 × Salata s piletinom (9,00 €) i 2 × Limunada (3,00 €), na 6,5 km, s kodom STUDENT10. Šta vraćaju artikli(), dostava() i ukupno() (u centima)?

Rješenje. artikli = 2 × 900 + 2 × 300 = 2400 centi (24,00 €). Dostava: 24,00 € < 30,00 €, a preko 3 km je 3,5 km, dakle četiri započeta kilometra: 200 + 4 × 50 = 400 centi (4,00 €). Popust: 10 % od 2400 = 240 centi (manje od 500). ukupno = 2400 − 240 + 400 = 2560 centi = 25,60 €.

Vježba za studenta 5 – nedostajuće pravilo.

Kupac K-01 je naručio N-1001 kad je Margarita koštala 9,50 €. Sedmicu kasnije restoran je poskupi na 10,00 € i kupac otvori istoriju narudžbi. Šta pokazuje model iz 6.8 bez dodatka iz koraka 2, a šta s dodatkom? Kako se to zove u projektovanju?

Rješenje. Bez dodatka stavka pokazuje na jelo, pa bi se ukupno ponovo izračunalo s novom cijenom: 2 × 10,00 + 2,50 + 3,00 = 25,50 €, što nije iznos koji je kupac platio (24,50 €). S atributom cijena_u_trenutku stavka pamti 950 centi, pa istorija pokazuje tačnih 24,50 €. Ovo je primjer da se istorijski podaci zamrzavaju u trenutku transakcije; to je poslovno pravilo koje je otkrio model, a ne korisnik.

Sažetak u pet rečenica

  1. Objekat je konkretna stvar u sistemu sa stanjem, ponašanjem i identitetom, a klasa je opis po kojem se prave objekti iste vrste, ideja koja potiče iz jezika Simula iz 1967.
  2. U UML-u klasa je pravougaonik s imenom, atributima i operacijama, a enkapsulacija skriva podatke tako da se mijenjaju samo kroz operacije koje provjeravaju pravila.
  3. Asocijacija s višestrukošću (1, 0..1, 0.., 1..) čita se kao rečenica u oba smjera, kompozicija znači da dio ne postoji bez cjeline, a nasljeđivanje da je posebna klasa vrsta opšte.
  4. Klase se nalaze analizom teksta, a domenski model DeliveryApp ima devet klasa i otkrio je novo pravilo da stavka pamti cijenu u trenutku narudžbe.
  5. Isti model napisan kao Python klase računa za N-1001 2150 centi artikala, 300 centi dostave i ukupno 24,50 €, a dijagram objekata provjerava model na stvarnom primjeru.

Pitanja za ponavljanje

  1. Ko su bili Dahl i Nygaard i šta je donio jezik Simula?
  2. Koje tri osobine ima objekat? Objasnite ih na narudžbi N-1001.
  3. Objasnite razliku između klase i objekta pomoću kalupa za kolače.
  4. Kako se klasa crta u UML-u? Šta znače znakovi + i −?
  5. Šta je enkapsulacija i zašto je stanje narudžbe privatno?
  6. Šta je asocijacija i šta je višestrukost? Navedite četiri oznake višestrukosti.
  7. Pročitajte u oba smjera vezu između kupca i narudžbe.
  8. Koja je razlika između kompozicije i agregacije? Dajte primjer za svaku.
  9. Šta je nasljeđivanje i koja dva testa pokazuju da je pogrešno upotrijebljeno?
  10. Šta znači „radije sastavljaj nego nasljeđuj”?
  11. Kako se analizom teksta dolazi do klasa? Navedite tri pravila sortiranja kandidata.
  12. Šta je domenski model i ko ga treba razumjeti?
  13. Zašto stavka treba pamtiti cijenu u trenutku narudžbe?
  14. Šta je dijagram objekata i čemu služi?

Odgovori na pitanja za ponavljanje.

  1. Ole-Johan Dahl i Kristen Nygaard su norveški naučnici koji su u Norveškom računskom centru u Oslu radili simulacije. Njihov jezik Simula (verzija iz 1967) bio je prvi jezik s klasama, objektima i nasljeđivanjem; za to su 2001. dobili Turingovu nagradu.
  2. Stanje (podaci: broj N-1001, kupac K-01, restoran R-1, 4,2 km, dvije stavke, stanje NOVA), ponašanje (zna dodati stavku, izračunati ukupno i promijeniti stanje) i identitet (to je baš ova narudžba, različita od neke druge s istim stavkama).
  3. Klasa je kao kalup: određuje oblik, ali se ne jede. Objekti su kolači napravljeni po kalupu: svaki ima isti oblik, ali svoje vrijednosti (nadjev). Klasa Narudžba ne košta ništa, a narudžba N-1001 košta 24,50 €.
  4. Kao pravougaonik s tri dijela: ime, atributi (ime: tip) i operacije (ime(parametri): tip). Znak + znači javno (svi smiju koristiti), a − privatno (samo sam objekat).
  5. Enkapsulacija znači da objekat skriva svoje podatke i mijenja ih samo kroz operacije koje provjeravaju pravila. Stanje narudžbe je privatno da ga niko ne bi mogao postaviti mimo pravila PP-6; mijenja se samo operacijom promijeni(), koja provjerava dozvoljene prelaze.
  6. Asocijacija je veza koja kaže da se objekti dvije klase poznaju. Višestrukost kaže koliko objekata s jedne strane može biti povezano s jednim objektom s druge: 1, 0..1, 0..* i 1..*.
  7. Jedan kupac pravi nula ili više narudžbi; jedna narudžba pripada tačno jednom kupcu.
  8. Kod kompozicije dio ne postoji bez cjeline i briše se s njom (stavka i narudžba; sobe i kuća). Kod agregacije dio postoji i sam (dostavljač i tim; igrači i fudbalski tim).
  9. Nasljeđivanje znači da posebna klasa preuzima sve od opšte i dodaje svoje. Pogrešno je ako rečenica „B je vrsta A” zvuči čudno (test „je vrsta”) ili ako posebna klasa ne može bez iznenađenja zamijeniti opštu (test zamjene).
  10. Da je često bolje da objekat ima drugi objekat (kupac ima adresu) nego da nasljeđuje klasu samo zbog zajedničkih podataka.
  11. Iz vizije, priča i specifikacija podvuku se imenice (kandidati za klase i atribute) i glagoli (kandidati za operacije i veze). Pravila: ono što se računa nije atribut nego operacija; vanjski sistemi nisu klase domena; riječ „sistem” se odbacuje.
  12. Domenski model je dijagram klasa s pojmovima posla i njihovim vezama, bez tehničkih detalja. Treba ga razumjeti i čovjek iz posla, npr. vlasnik restorana, koji potvrđuje rečenice veza.
  13. Da bi istorija narudžbi pokazivala iznos koji je kupac zaista platio. Ako restoran kasnije promijeni cijenu jela, već plaćena narudžba ne smije promijeniti iznos.
  14. Dijagram objekata prikazuje stvarne objekte i njihove vrijednosti u jednom trenutku. Služi za provjeru modela: ako se ne može nacrtati stvaran primjer, model ima rupu.