Deo zbornika Uvod u softversko inženjerstvo
Posrednik (projektni obrazac)
Posrednik (proxy) jeste objekat koji kontroliše pristup drugom objektu, koji nazivamo subjekat. Posrednik i subjekat imaju identičan interfejs, što omogućava da jedan zamenjujemo drugim. Posrednik presreće sve ili neke operacije koje treba da se izvrše nad subjektom, čime proširuje ili dopunjuje njegovo ponašanje.
Upotreba
Posrednički obrazac se obično koristi u sledećim slučajevima:
- Kontrola pristupa: posrednik može da ograniči pristup resursima tako što proverava dozvole ili autentifikaciju korisnika pre nego što dozvoli pristup originalnom objektu.
- Optimizacija resursa: Kada rad sa originalnim objektom zahteva znatne resurse, posrednik može da optimizuje učitavanje tako što koristi lazy initialization i kreira originalni objekat samo kada je neophodno.
- Logovanje ili nadgledanje: posrednik može da služi za praćenje poziva metoda originalnog objekta, što može biti korisno za analitiku, sigurnosne provere ili otklanjanje grešaka.
- Rad sa udaljenim objektima (remote proxy): Kada je objekat na udaljenom serveru, možemo kreirati lokalnog posrednika koji upravlja pozivima na serveru, omogućujući lakšu komunikaciju.
Primeri
Posrednik za lenjo učitavanje
Recimo da imamo objekat koji učitava veliku sliku prilikom instanciranja. Kreiraćemo ImageProxy
klasu koja će učitati sliku tek kada korisnik zatraži njen prikaz:
class RealImage {
constructor(filename) {
this.filename = filename
this.loadFromDisk()
}
loadFromDisk() {
console.log(`Učitavanje slike sa diska: ${this.filename}`)
}
display() {
console.log(`Prikaz slike: ${this.filename}`)
}
}
class ImageProxy {
constructor(filename) {
this.filename = filename
this.realImage = null
}
display() {
if (!this.realImage) {
this.realImage = new RealImage(this.filename)
}
this.realImage.display()
}
}
const image = new ImageProxy('velikaSlika.jpg')
image.display() // tek sad učitava
Posrednik za praćenje pristupa
Ovaj primer koristi funkciju koja omogućava praćenje pristupa svojstvima objekta:
const createProxy = target => ({
get(prop) {
const vrednost = prop in target ? target[prop] : 'Nepoznato svojstvo'
console.log(`Pokušan pristup za ${prop}:`, vrednost)
},
set(prop, value) {
console.log(`Postavljena vrednost za ${prop}: ${value}`)
target[prop] = value
}
})
const osoba = { ime: 'Marko', prezime: 'Marković' }
const proxy = createProxy(osoba)
proxy.get('ime')
proxy.get('mesto')
proxy.set('mesto', 'Beograd')
U Javaskriptu postoji i Proxy klasa koju možemo koristiti da kreiramo posrednika:
const osoba = {
ime: 'Marko',
prezime: 'Marković'
}
const proxy = new Proxy(osoba, {
get(target, prop) {
const vrednost = prop in target ? target[prop] : 'Nepoznato svojstvo'
console.log(`Pokušan pristup za ${prop}:`, vrednost)
}
})
proxy.ime
proxy.mesto
Posrednik za validaciju vrednosti
const broj = {
vrednost: 0
}
const proxy = new Proxy(broj, {
set(target, prop, value) {
if (prop === 'vrednost' && value < 0) {
console.log('Vrednost ne može biti negativna!')
return
}
target[prop] = value
console.log('Uspešno setovano.')
}
})
proxy.vrednost = 10
proxy.vrednost = -5
Posrednik za keširanje
Ovde koristimo proxy obrazac za keširanje videa - createProxyDownloader
proverava keš i preuzima novi video samo ako nije keširan, inače vraća keširanu verziju.
const downloadVideo = async name => {
console.log("Connecting to https://www.youtube.com/")
await new Promise(resolve => setTimeout(resolve, 500 + Math.random() * 1000))
console.log("Downloaded", name)
return { name, downloaded: true }
}
const createProxyDownloader = () => {
const videoCache = new Map()
return async name => {
if (!videoCache.has(name))
videoCache.set(name, downloadVideo(name))
return videoCache.get(name)
}
}
// upotreba
const log = item => console.log(`Video "${item.name}" is ready and cached`)
const getVideo = createProxyDownloader()
getVideo("Geekific").then(log)
getVideo("Geekific").then(log)
getVideo("Sean Study").then(log)
getVideo("Sean Study").then(log)
getVideo("Geekific").then(log)
Posrednik za autorizaciju
U okviru proxy obrasca proveriti da li je korisnik uspešno autentifikovan na sistem, ako jeste, autorizovati plaćanje kreditnom karticom, a ako nije izbaciti poruku.
const pay = () => {
console.log("Plaćanje je izvršeno.")
}
const createProxy = authenticated => {
return () => {
if (authenticated)
pay()
else
console.log("Morate se ulogovati pre plaćanja.")
}
}
// upotreba
const authenticatedPay = createProxy(true)
authenticatedPay()
const unauthenticatedPay = createProxy(false)
unauthenticatedPay()
Literatura
- Mario Casciaro, Luciano Mammino, Node.js: Projektni obrasci, Mikro knjiga, 2019.
- Angelina Njeguš, Obrasci projektovanja softvera, Univerzitet Singidunum, Beograd, 2023.