Прокси-шаблон: как это более эффективно, чем создание реального объекта?

1

В следующем примере из wiki-книг https://en.wikibooks.org/wiki/Computer_Science_Design_Patterns/Proxy

Я не уверен, что это быстрее/эффективнее, чем просто создание реального объекта и использование отображаемого изображения из него. Постепенно proxy создает реальный объект в любом случае в методе displayImage?

//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();
        }

    }

Конечно, прокси-шаблон не сохранил бы память, поскольку для создания двух объектов (прокси и реального), а не только одного (реального), если вы не использовали прокси-сервер, ему нужно создать экземпляр двух объектов (прокси и реальный)?

  • 0
    Это сэкономит память при объявлении, вот и все. Возможно, это того не стоит, но вы можете добавить методы bind () и release () для динамического выделения памяти изображениям.
  • 0
    Как это сэкономит память? Я не думаю, что я понимаю эту модель очень хорошо
Показать ещё 2 комментария
Теги:
design-patterns
proxy-pattern

2 ответа

3
Лучший ответ

Из ссылки, которую вы опубликовали (акцент мой):

Прокси-класс ProxyImage работает в другой системе, чем сам реальный класс изображения, и может представлять реальный образ RealImage. Информация об изображении поступает с диска. Используя прокси-шаблон, код ProxyImage позволяет избежать множественной загрузки изображения, обращаясь к нему из другой системы с сохранением памяти.

Короче говоря: он не экономит память, это ускоряет работу приложения, потому что вам не нужно каждый раз обращаться к диску, чтобы прочитать реальный образ.

Это доказано в этой части кода:

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();
}

Чтобы лучше понять эту проблему, измените определения класса и интерфейса:

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

Теперь класс RealImage, который всегда будет искать данные на диске, если файл не существует (он был удален или переименован):

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;
    }
}

И теперь, наш хороший ProxyImage который будет выступать в качестве прокси для RealImage для сохранения дорогостоящей задачи перехода на диск каждый раз, сохраняя данные в памяти:

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;
    }
}

Таким образом, отражая RealImage использования прокси для нашего RealImage.

  • 0
    То есть, вместо того, чтобы создавать изображение, которое вы не можете использовать, вы создаете его, только если хотите его отобразить?
  • 0
    @ RNI2013 Да, и если вам это нужно несколько раз, вы не создадите его снова с диска, вы будете использовать его повторно.
Показать ещё 9 комментариев
1

Цель этого конкретного прокси-сервера состоит в том, чтобы реализовать то, что называется "Lazy Loading". Он фактически не читает файл и не создает изображение в памяти, пока какой-либо другой фрагмент кода не попытается его отобразить. Это могло бы сэкономить много времени и памяти по сравнению с помещением изображений в память, которые вы никогда не используете!

В небольших примерах легко подумать: "Ну, я мог просто запрограммировать умных и не загружать глупую вещь". Но представьте себе большую систему, в которой вы застряли с API, который принимает List<Image> в качестве аргумента, но на самом деле рисует его только тогда, когда пользователь нажимает имя файла или что-то в этом роде. Это может стать значительным стимулом.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню