Dizajn paterni Factory, Abstract Factory, State, Model-View-Presenter, Proxy
dr Zoran Jeremić
[email protected]
1
Paterni kreiranja
SIMPLE FACTORY, FACTORY METHOD I ABSTRACT FACTORY 2
Kada treba koristiti factory paterne Kada niste sigurni koju konkretnu implementaciju određenog interfejsa želite da vratite, Kreriranje treba da bude odvojeno od reprezentacije objekta, Imamo puno if/else blokova koji odlučuju koju konkretnu klasu treba kreirati Imamo puno switch iskaza koji odlučuju koju konkretnu klasu treba kreirati.
3
Simple Factory Enkapsulira kreiranje objekta Omogućava donošenje kasnih odluka u vezi sa instaciranjem objekta Na osnovu konfiguracije Na osnovu perzistentnih podataka Na osnovu ulaza ili drugih dinamičkih podataka
Klasa pozivalac zna koji konkretni factory joj treba
4
Opis problema Kada koristimo new mi zapravo instanciramo konkretnu klasu, tako da je to definitivno implementacija a ne interfejs. Duck duck = new MallardDuck();
Kada imamo skup povezanih konkretnih klasa, često pišemo kod poput ovog: Duck duck; If (picnic) { duck = new MallardDuck(); } else if (hunting) { duck = new DecoyDuck(); }else if (inBathTub){ duck = new RubberDuck(); } 5
Opis problema Kod pisan kroz interfejse će raditi kroz polimorfizam sa bilo kojom novom klasom koja implementira interfejs. Međutim kada imamo dosta konkretnih klasa, kod se mora menjati dodavanjem novih konkretnih klasa.
6
Opis problema
Pizza orderPizza(){ Pizza pizza;
Zbog fleksibilnosti Pizza je abstraktna klasa
pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; }
7
Opis problema Pizza orderPizza(String type){ Pizza pizza = new Pizza (); if (type.equals(“cheese”)) { pizza = new CheesePizza(); } else if (type.equals(“greek”) { pizza = new GreekPizza(); } else if (type.equals(“pepperoni”) { pizza = new PepperoniPizza(); } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza;
Sada prosleđujemo vrstu pice kao argument Na osnovu vrste pice instanciramo konkretnu klasu i dodeljujemo je promenljivoj pizza
} 8
Opis problema Pizza orderPizza(String type){ Pizza pizza = new Pizza (); if (type.equals(“cheese”)) { pizza = new CheesePizza(); } else if (type.equals(“greek”) { pizza = new GreekPizza(); } else if (type.equals(“pepperoni”) { pizza = new PepperoniPizza(); } else if (type.equals(“clam”)) { pizza = new ClamPizza(); } else if (type.equals(“veggie”) { pizza = new VeggiePizza(); } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; }
Kod se mora konstantno menjati u skladu sa ponudama picerije
Ovo nije u skladu sa Open-Closed principom
9
Enkapsulacija kreiranja objekta
Pizza orderPizza(String type){ Pizza pizza = new Pizza ();
if (type.equals(“cheese”)) { pizza = new CheesePizza(); } else if (type.equals(“pepperoni”) { pizza = new PepperoniPizza(); } else if (type.equals(“clam”)) { pizza = new ClamPizza(); } else if (type.equals(“veggie”) { pizza = new VeggiePizza(); }
pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; }
10
Jednostavan pizza factory public class SimplePizzaFactory { public Pizza createPizza(String type) { Pizza pizza = null; if (type.equals(“cheese”)) { pizza = new CheesePizza(); } else if (type.equals(“pepperoni”)) { pizza = new PepperoniPizza(); } else if (type.equals(“clam”)) { pizza = new ClamPizza(); } else if (type.equals(“veggie”)) { pizza = new VeggiePizza(); } return pizza; } }
Metodu createPizza() koriste svi klijenti za instanciranje novih objekata. Ovaj kod je još uvek parametrizovan vrstom pice, kao i u originalnoj orderPizza() metodi.
11
PizzaStore klasa public class PizzaStore { SimplePizzaFactory factory; public PizzaStore(SimplePizzaFactory factory) { this.factory = factory; }
PizzaStore klasi se prosleđuje factory kroz konstruktor
public Pizza orderPizza(String type) { Pizza pizza; pizza = factory.createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza;
orderPizza() metoda koristi factory da kreira picu jednostavnim prosleđivanjem tipa pice
} // other methods here } 12
Dijagram klasa
13
Factory Method Factory method patern definiše interfejs za kreiranje objekta, ali omogućava podklasama da odluče koja klasa će se instancirati. Factory Method delegira odgovornost za instanciranje klasa na podklase. Dodaje interfejs samom Factory-ju iz Simple Factory-ja Prenosi odgovornost za kreiranje objekta na veći broj Factory-ja koji dele interfejs
14
Šta sa regionalnim razlikama? Picerije u različitim gradovima mogu imati različite vrste pica u ponudi.
Jedan pristup je da umesto SimplePizzaFactory kreiramo tri različite fabrike, NYPizzaFactory, ChicagoPizzaFactory i CaliforniaPizzaFactory. 15
16
17
Omogućiti podklasama da odluče
18
Jedna od podklasa se poziva
19
20
Prednosti i nedostaci Factory method paterna Prednosti
Nedostaci
Eliminiše reference na konkretne klase (Factory i objekte koje su kreirale Factory klase)
Može biti potrebno da se kreira factory samo da bi se dobile konkretne klase
Factory klase se mogu proširivati da bi obezbedile još specijalizovanije kreiranje objekata
Hijerarhija nasleđivanja ide sve dublje zbog povezivanja konkretnih factory klasa i kreiranih klasa.
Pravila za inicijalizaciju objekata su centralizovana
Struktura Factory Method paterna
23
Abstract Factory Abstract factory patern obezbeđuje interfejs za kreiranje familija vezanih ili zavisnih objekata bez definisanja njihovih konkretnih klasa.
Factory kreiraju različite vrste konkretnih objekata (proizvoda) Factory predstavlja familiju objekata koji se mogu kreirati Factory mogu imati više od jednog factory metoda
24
25
26
Paterni ponašanja
STATE PATERN
27
Motivacija: Mašina za loptice
• Definisanje vrednosti za svako stanje
• Akcija i promena stanja
29
Trenutno stanje implementirane mašine Nema enkapsulacije Nije objektno orjentisan Prelazi između stanja nisu eksplicitni i smešteni su unutar velikog broja uslovnih iskaza Dalje proširivanje daje veliko verovatnoću da izavove bagove
Rešenje Potrebno je enkapsulirati objekte stanja u sopstvene klase i delegirati trenutno stanje kada dođe do akcije. Najpre definišemo State interfejs koji sadrži metode za svaku akciju Gumball mašine Zatim implementiramo State klasu za svako stanje mašine. Ove klase će biti odgovorne za ponašanje mašine kada se nalazi u odgovarajućem stanju. Konačno, oslobodićemo se uslovnog koda i delegirati klasi stanja da radi za nas.
34
35
Klasa stanja
36
Klasa Gumball mašine Stari kod
Izmenjen kod
37
Implementacija Gumball mašine
38
Implementacija Gumball mašine
39
Implementacija stanja
40
Implementacija stanja
41
Promena stanja
42
Definicija i struktura State paterna
State patern omogućava objektu da promeni svoje ponašanje kada mu se promeni unutrašnje stanje. Objekat će promeniti svoju klasu.
43
MODEL-VIEW-PRESENTER
44
Motivacija
45
Namena Obezbeđuje jasno razdvajanje između: Podataka koje treba prikazati Poslovne logike aplikacije Prikaza poadataka
Obezbeđuje da svaki učestnik u paternu ima samo jednu odgovornost Model View Prezenter
Omogućava izolovano testiranje svakog učesnika u paternu 46
Struktura View i Model ne znaju ništa jedno o drugome Presenter koordinira zahteve i događaje između Modela i View komponente
47
Struktura
• Svi MVP učesnici su deo UI sloja • Model nije deo poslovnog domena • Model je specijalna prezentacija podataka napravljena specijalno za View
48
Kolaboracija Model Čuva podatke koje će prikazati View
View
Instancira Presenter komponentu Zahteva da Prezenter izvrši zadatak Može imati referencu na Model ili se može osloniti na Presenter da inicijalizuje podatke
Presenter Odgovara na zahteve View komponente Može znati kada su podaci ažurirani Ažurira View podacima iz Modela 49
Posledice Svaku klasu je moguće testirati odvojeno od drugih Jasna podela odgovornosti, pri čemu svaki učesnik ima samo jednu odgovnorst
50
Strukturni paterni
PROXY PATERN
51
Kontrolisanje pristupa objektu Dobar policajac – loš policajac Dobar policajac pruža sve usluge na ljubazan i prijateljski način, ali ne želi da mu svi traže usluge, pa zbog toga ima lošeg policajca koji kontroliše pristup dobrom policajcu. To je ono što proxy radi: kontroliše i upravlja ko može da pristupi nekom objektu.
52
Gumball mašina Dodavanje podrške za upravljanje lokacijom Gumball mašine.
53
Gumball monitor
54
Testiranje monitora
55
Primenljivost Remote proxy ima ulogu lokalnog predstavnika udaljenog objekta. To je objekat nad kojim možete lokalno pozivati metode i usmeravati ih ka udaljenom objektu.
Klijentski objekat se ponaša kao da se pozivaju udaljene metode, ali ono što se u stvari dešava je pozivanje metoda na lokalnom proxy-ju koji upravlja svim detaljima mrežne komunikacije.
56
Primenljivost Virtual proxy kreira skupi objekat na zahtev. Tipičan primer je Image Proxy koji prikazuje placeholder dok se slika učitava ili renderuje. Protection proxy se može koristiti za kontrolu pristupa objektu, na osnovu pravila o autorizaciji.
57
Definicija i struktura Proxy paterna Proxy patern obezbeđuje surogat ili placeholder za drugi objekat i kontroliše pristup tom objektu.
58
Struktura (alternativna)
59
Kako se koristi Klijenti rade sa Proxy objektom kao da je reč o stvarnom objektu Proxy kontroliše pristup stvarnom objektu, delegirajući pozive ka njemu kada je potrebno Koristi se da: Unapredi performanse i vreme pokretanja aplikacije Pojednostavljuje interakciju sa udaljenim objektom Odlaže skupe pozive dokle god je to moguće – implementira lazy loading objekata iz perzistentnog skladišta
60
Posledice Klijentski kod se ne mora menjati da bi radilo sa Proxyjem Ipak, Proxy mora biti sinhronizovan sa stvarnim objektom
Proxy se može koristiti da optimizuje performanse postojećeg sistema bez izmene ponašanja postojeće klase Poštuje se Open/Closed princip
Klijentski kod može imati pogrešne pretpostavke o ponašanju stvarnog objekta Interfejs može koristiti više malih poziva umesto jednog velikog Pristup klijentu korišćenjem lazy loadinga može rezultirati u većem broju pristupa bazi podataka nego što je potrebno. 61