В следующем примере из 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();
}
}
Конечно, прокси-шаблон не сохранил бы память, поскольку для создания двух объектов (прокси и реального), а не только одного (реального), если вы не использовали прокси-сервер, ему нужно создать экземпляр двух объектов (прокси и реальный)?
Из ссылки, которую вы опубликовали (акцент мой):
Прокси-класс
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
.
Цель этого конкретного прокси-сервера состоит в том, чтобы реализовать то, что называется "Lazy Loading". Он фактически не читает файл и не создает изображение в памяти, пока какой-либо другой фрагмент кода не попытается его отобразить. Это могло бы сэкономить много времени и памяти по сравнению с помещением изображений в память, которые вы никогда не используете!
В небольших примерах легко подумать: "Ну, я мог просто запрограммировать умных и не загружать глупую вещь". Но представьте себе большую систему, в которой вы застряли с API, который принимает List<Image>
в качестве аргумента, но на самом деле рисует его только тогда, когда пользователь нажимает имя файла или что-то в этом роде. Это может стать значительным стимулом.