Proxy
Popis Klient má přístup k nějakému objektu Potřebujeme tento přístup ošetřit, aniž bychom přidělali klientovi práci Kontrola přístupu Vzdálený přístup Cachování Load on demand
Struktura ÚČASTNÍCI Subject Společné rozhraní RealSubject Skutečný objekt Proxy Stejné rozhraní jako real subject Má pointer na real subject, předává mu requesty, kontroluje přístup...
Motivace Příklad Prohlížeč obrázků Seznam všech obrázků ve složce a jejich zobrazení Špatný přístup - získáme seznam obrázků a všechny fotky nahrajeme do paměti Lepší řešení – zobrazení fotky na vyžádání (load on demand) Elegantní realizace řešení – PROXY
Prohlížeč obrázků Interface Image { void ShowImage() ; Size GetSize(); }; Interface Image { void ShowImage() ; Size GetSize(); }; class RealImage implements Image { public RealImage(fileName) { // skutecne nacitani obrazku z disku // pomale loadImage(fileName); } public void ShowImage() { // renderovani obrazku } public Size GetSize(fileName) { return new Size(data.cols, data.rows); } }; class RealImage implements Image { public RealImage(fileName) { // skutecne nacitani obrazku z disku // pomale loadImage(fileName); } public void ShowImage() { // renderovani obrazku } public Size GetSize(fileName) { return new Size(data.cols, data.rows); } }; public class ImageProxy : Image { String fileName; Image proxifiedImage; public ImageProxy(String fileName) { this.fileName = fileName; } public void ShowImage() { if (proxifiedImage == null) proxifiedImage = new RealImage(fileName); proxifiedImage.showImage(); } public Size GetSize() { return HeaderInfo.LoadSize(fileName); } }; public class ImageProxy : Image { String fileName; Image proxifiedImage; public ImageProxy(String fileName) { this.fileName = fileName; } public void ShowImage() { if (proxifiedImage == null) proxifiedImage = new RealImage(fileName); proxifiedImage.showImage(); } public Size GetSize() { return HeaderInfo.LoadSize(fileName); } }; Interface Proxy RealObject ImageProxy img1 = new ImageProxy(“img1.png”); ImageProxy img2 = new ImageProxy(“img2.png”); Console.WriteLine(img2.GetSize()); Img1.ShowImage(); ImageProxy img1 = new ImageProxy(“img1.png”); ImageProxy img2 = new ImageProxy(“img2.png”); Console.WriteLine(img2.GetSize()); Img1.ShowImage();
Proxy - typy Virtual proxy Vytváření objektů až v případě potřeby („load on demand“) Transparentní provádění optimalizací (Cache proxy, Copy-on-write proxy) Remote proxy Lokální zástupce vzdáleného objektu Middleware: Java RMI, CORBA, XML/SOAP,... Protection proxy Kontrola či omezování přístupů ke skutečnému objektu Synchronization proxy Synchronizace vláken před voláním metod objektu Smart pointers/reference Náhrada běžných ukazatelů (např. v C++) či referencí Počítání referencí a automatické odalokování Načítání do paměti při první dereferenci „protection proxy“
Proxy – implementace Abstraktní proxy pro subjekty více typů Pracuje-li se skutečným objektem jen pomocí rozhraní, může být typově nezávislá Konkrétní instanci lze přiřadit např. v konstruktoru: Přetížení „->“ v C++ jako proxy Stejná obsluha všech požadavků Virtual proxy – ImagePtr, Real Subject – Image Implementace: Image* ImagePtr::LoadImage () { if (image_ == 0) image_ = LoadFile(_imageFile); return image_; } Image* ImagePtr::operator-> () { return LoadImage(); } Image& ImagePtr::operator* () { return *LoadImage(); } Použití: ImagePtr image = ImagePtr("ImgFileName"); image->Draw(Point(0, 0)); // (image.operator->())->Draw(Point(0, 0)) Graphic * g = new GraphicProtectionProxy(new Image);
Protection proxy - Java Řešení problému absence const v Javě: Omezená rozhraní Protection proxies (wrappers) public interface java.util.Collection { boolean contains(Object o); boolean add(E o); //.... } public class UnmodifiableCollection implements Collection { private Collection c; public UnmodifiableCollection(Collection c) { this.c = c; } public boolean contains(Object o) { return c.contains(o); } public boolean add(E o) { throw new UnsupportedOperationException(); } //... } public static Collection unmodifiableCollection(Collection c) { return new UnmodifiableCollection (c); } // vytvoření seznamu List lst = new ArrayList(); // příprava dat apod. // nyní se vytvoří neměnná kolekce Collection c = Collections.unmodifiableCollection(lst);
Synchronization proxy - Java Standardní kolekce nejsou v Javě thread-safe Umožňuje vyšší rychlost Volitelné řešení: synchronization proxies (wrappers) Myšlenkově identické s předchozí unmodifiableCollection public class SynchronizedCollection implements Collection { private Collection c; private Object myLock; public SynchronizedCollection(Collection c) { this.c = c; } public boolean contains(Object o) { synchronized(myLock) {return c.contains(o);} } public boolean add(E o) { synchronized(myLock) {return c.add(o);} } //... } public static Collection synchronizedCollection(Collection c) { return new SynchronizedCollection (c); } // typický příklad List l = Collections.synchronizedList(new LinkedList());
Známé využití - Java RMI (Remote Method Invocation) public interface HelloIntf extends Remote { public String sayHello() throws RemoteException; } public class Hello extends UnicastRemoteObject implements HelloIntf { public Hello() throws RemoteException { } public String sayHello() throws RemoteException { return "Hello World!"; } public class Server { public static void main(String[] args) { try { Naming.rebind("Hello", new Hello()); } catch (Exception e) { } } public class Client { public static void main(String[] args) { try { HelloIntf hello =(HelloIntf)Naming.lookup("/localhost/Hello"); System.out.println(hello.sayHello()); } catch (Exception e) { } }
Proxy +/- Výhody Zjednodušení cílového kódu Zapouzdření optimalizací a strategie přistupování k objektu Oddělení administrativního kódu od funkcionality Transparentní a snadný návrhový vzor Nevýhody Snižení efektivity – vrstva navíc, reference navíc Tvorba sady proxy pro větší subsystém může být zdlouhavá Řešení: automatizace pomocí např. Reflection – opět citelné zpomalení Lepší řešení: vytvoření Fasády pro subsystém a jediné proxy (možno sloučit) Klient o proxy vrstvě jakoby neví – nezná možné vedlejší účinky (připojování k síti, náročné operace)
Proxy - související NV Adapter Také tvoří mezivrstvu Adaptuje jedno rozhraní na druhé odlišné Proxy implementuje identické rozhraní jako skutečný objekt Decorator Podobná struktura, ale jiný účel - přidává funkčnost Musí po celou dobu běhu držet fyzickou instanci skutečného objektu U proxy ještě nemusí existovat či může být např. na jiném počítači