Proxy

Design patterns / Structural patterns
image

//Subject: a pointer to a function plays the virtual draw()
typedef struct Graphic {
    const char *fileName;
    void (*draw)(struct Graphic *self);
} Graphic;

//RealSubject: it is costly to create
typedef struct {
    Graphic base;
} Image;

//Request()
void imageDraw(Graphic *self) {
    printf("draw %s\n", self->fileName);
}

Image *imageNew(const char *fileName) {
    printf("load %s\n", fileName);
    Image *image = malloc(sizeof *image);
    *image = (Image){{fileName, imageDraw}};
    return image;
}

//Proxy: the same Subject, the real image is made on the first draw()
typedef struct {
    Graphic base;
    Image *image;
} ImageProxy;

Image *getImage(ImageProxy *proxy) {
    if (proxy->image == nullptr) {
        proxy->image = imageNew(proxy->base.fileName);
    }
    return proxy->image;
}

void proxyDraw(Graphic *self) {
    Graphic *image = &getImage((ImageProxy *)self)->base;
    image->draw(image);
}

//Client
ImageProxy proxy = {{"1.png", proxyDraw}, nullptr};
Graphic *graphic = &proxy.base;
//operation without creating a RealSubject
const char *fileName = graphic->fileName;
//forwarded to the RealSubject
graphic->draw(graphic);
//printed: load 1.png
//         draw 1.png
graphic->draw(graphic);
//printed: draw 1.png

printf("fileName: %s\n", fileName);
free(proxy.image);


Provide a surrogate or placeholder for another object to control access to it. The proxy implements the interface of the original object.
Read more

The problem. A document contains many large pictures. If the program loads all of them when the document opens, opening is slow, although the user sees only the first page. The code that shows the pictures should stay the same. But loading must wait until a picture is really needed.

The idea. A proxy takes the place of another object, the real subject. It has the same interface, so the client sees no difference between them. The proxy decides when and how the real subject is used. This kind, a virtual proxy, creates the real subject only on the first request and then forwards every call to it. Other kinds of proxy check access rights, keep a cache or reach an object on another computer.

How to read the example. The real subject is an image that is costly to create. The proxy keeps only the file name and an empty place for the image. In most languages the client first asks for the file name, and the proxy answers alone. When the client asks to draw, the proxy creates the real image, keeps it and forwards the call. The client works only with the proxy. In some languages the output also shows the moment when the real image is loaded.

When to use it. Use Proxy to control access to an object without changing the object or its clients. Typical tasks are to delay a costly creation, to check rights or to count calls. Do not use it when the object is cheap and always needed: the extra level only slows the code.

A common mistake. Not keeping the created object. The proxy then creates a new real subject on every call, and the saving is lost.