Question

In the following example, from wiki books https://en.wikibooks.org/wiki/Computer_Science_Design_Patterns/Proxy

I am not sure how this is faster/more effiecent than just creating the real object and using display image from it. Becuase the proxy creates the real object anyway within the displayImage method?

//on System B
    class ProxyImage implements Image {

        private RealImage image = null;
        private String filename = null;
        /**
         * Constructor
         * @param FILENAME
         */
        public ProxyImage(final String FILENAME) {
            filename = FILENAME;
        }

        /**
         * Displays the image
         */
        public void displayImage() {
            if (image == null) {
               image = new RealImage(filename);
            }
            image.displayImage();
        }

    }

Surely the proxy pattern wouldnt save memory as it needs to instantiate two objects (proxy and real) rather than just one (real) if you didnt use proxy?

Was it helpful?

Solution

From the link you posted (emphasis mine):

The proxy class ProxyImage is running on another system than the real image class itself and can represent the real image RealImage over there. The image information is accessed from the disk. Using the proxy pattern, the code of the ProxyImage avoids multiple loading of the image, accessing it from the other system in a memory-saving manner.

In short: it doesn't save memory, it speeds up the application because you don't need to access to disk every time to read the real image.

This is proven in this part of the code:

public void displayImage() {
    //if image is not loaded into memory
    if (image == null) {
        //then load it, go to disk only once
        image = new RealImage(filename);
    }
    //now it is in memory, display the real image
    image.displayImage();
}

To have a better understanding of this problem, let's change the definitions of the class and the interface:

public interface Image {
    String getName();
    byte[] getData();
}

Now, the RealImage class that will always seek for the data in disk, in case the file doesn't exist (it was deleted or renamed):

public class RealImage implements Image {
    //implements all the operations going to disk...
    private String fileName;
    public RealImage(String fileName) {
        this.fileName = fileName;
    }
    @Override
    public String getName() {
        String name = "";
        //fancy operations to seek for the file in disk (in case it has been deleted)
        //read the data from file in disk
        //get the name
        name = ...;
        return name;
    }
    @Override
    public byte[] getData() {
        byte[] data;
        //again, fancy operations to seek for the file in disk (in case it has been deleted)
        //read the data from file in disk
        //get the image data for displaying purposes
        data = ...;
        return data;
    }
}

And now, our good ProxyImage that will act as a proxy for a RealImage to save the highly costly task of going to disk every time by saving the data into memory:

public class ProxyImage implements Image {
    private String fileName;
    private RealImage realImage;
    private byte[] data;
    private String name;
    //implements all the operations going to disk...
    public RealImage(String fileName) {
        this.fileName = fileName;
    }
    @Override
    public String getName() {
        //in case we don't have the name of the image
        if (this.name == null) {
            //use a RealImage to retrieve the image name
            //we will create the instance of realImage only if needed
            if (realImage == null) {
                realImage = new RealImage(fileName);
            }
            //getting the image from the real image is highly costly
            //so we will do this only once
            this.name = realImage.getName();
        }
        return this.name;
    }
    @Override
    public byte[] getData() {
        //similar behavior for the data of the image
        if (this.data == null) {
            if (realImage == null) {
                realImage = new RealImage(fileName);
            }
            //highly costly operation
            this.data = realImage.getData();
        }
        return this.data;
    }
}

Thus reflecting the goodies of using a proxy for our RealImage.

OTHER TIPS

The purpose of this particular proxy appears to be to implement what's called 'Lazy Loading.' It doesn't actually read the file and create the image in memory until some other piece of code actually attempts to display it. This could save a lot of time and memory compared to putting images into memory that you never use!

In small examples it's easy to think "Well I could just program smarted and not load the silly thing." But imagine a bigger system where you are stuck with an API that takes a List<Image> as an argument, but only actually draws one when the user clicks the filename or something. This could be a significant boost.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top