Дизайн шаблона подходит для задачи - PullRequest
2 голосов
/ 24 января 2009

У меня есть требование сохранить файл изображения в различных форматах. Список форматов может изменяться довольно часто, поэтому я хотел бы, чтобы сохранение было очень расширяемым. Кроме того, сохранение может происходить во многих местах (жесткий диск, FTP, HTTP и т. Д.). Список сохраненных местоположений тоже будет меняться очень часто.

Я думал, что буду использовать базовый класс Image и много производных классов для каждого формата:

ImageBase {}
JpegImage : ImageBase {}
TiffImage : ImageBase{}

и обрабатывать сохранение в каждом подклассе соответствующим образом для форматирования. Это хорошее дизайнерское решение?

Кроме того, как я могу прикрепить расширяемый механизм сохранения механизм (FTP, общий доступ к файлам и т. Д.)?

Я бы хотел что-то вроде этого:

var image=ImageBase.GetImageFromDisk(path);
//some casting to subclass maybe??
var tiffImage=image as TiffImage;
tiffImage.Location=new FtpLocation();//not sure if this is a good idea
tiffImage.Save();

Проблема здесь в том, что конкретная реализация образа не должна знать или заботиться о месте сохранения. При вызове Save(); для подкласса изображения я хотел бы делегировать работу некоторому классу, например FtpLocation.

Посоветуйте, пожалуйста, как собрать кусочки.

Спасибо.

Valentin.

Ответы [ 6 ]

5 голосов
/ 24 января 2009

Во-первых, я бы реализовал потоки на вашем изображении. Таким образом, вы можете создать конструктор из потока и метод для создания потока для любого из ваших подклассов "image".

Кроме того, я бы создал вашу «сохраняющую» инфраструктуру, чтобы просто принимать потоки и записывать их в соответствующие методы (ftp, файл и т. Д.)

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

РЕДАКТИРОВАТЬ: Лично метод сохранения объекта типа данных звучит так, как будто он находится не в том месте, но, не зная всей вашей системы, я не могу сказать этого наверняка. Просто мой 2с.

1 голос
/ 24 января 2009

Я бы пошла немного другим путем. (Синтаксис Java.)

public class Image {
    public void load(byte[] imageData);
    public byte[] getImageData();
}

public class JpegImage extends Image {
    public void load(byte[] imageData) {
        /* decode image data. */
    }

    public byte[] getImageData() {
        /* encode and return the JPG data. */
    }
}

public class Location {
    public Image loadImage(String uri);
    public void saveImage(Image image);
}

public class HttpLocation extends Location {
    public Image loadImage(String uri) {
        byte[] = getData(uri);
        if (type == JPEG) {
            return new JpegImage().load(byte);
        } else if (type == PNG) {
            return new PngImage().load(byte);
        }
    }
    public void saveImage(Image image) {
        byte[] imageData = image.getImageData();
        /* upload. */
    }
}

Отображение типа контента веб-сервера на класс Image также может происходить более удобным способом в базовом классе Location (или совершенно другом вспомогательном классе), но это примерно то, как я это сделаю.

1 голос
/ 24 января 2009

Мне кажется, что конкретный класс должен иметь дело только с необработанными данными; это может быть запись в локальный файл (который затем обрабатывается базовым кодом) или в поток.

Например, что-то вроде:

public void Save()
{
    // TODO: add any language-specific constructs like "using", etc
    Stream stream = Location.OpenWrite();
    Save(stream);
    stream.Close();
}

protected abstract void Save(Stream stream);

Таким образом, Location отвечает за предоставление потока (который может быть потоком памяти, транспортным потоком, потоком временных файлов и т. Д.) И, при необходимости, за дополнительную работу, когда этот поток закрыт (путем инкапсуляции внутреннего поток через шаблон декоратора). Все, что делает подкласс - это запись в поток.

Загрузка немного сложнее, так как базовый класс должен предположительно (учитывая вашу предполагаемую статическую нагрузку от базового класса) взглянуть на поток, чтобы определить тип. Но в конечном итоге вы можете получить нечто подобное:

public static ImageBase Load(Location location)
{
    // TODO: add any language-specific constructs like "using", etc
    Stream stream = location.OpenRead();
    // TODO: wrap in a buffered/seekable stream so we can peek
    // TODO: parse headers and resolve image type
    ImageBase image = ...
    image.Location = location;
    stream.Position = 0; // rewind buffered/seekable stream
    // (don't use Load() since we have already opened the stream)
    image.Load(stream);
    stream.Close();
    return image;
}
protected abstract void Load(Stream stream);
public void Load()
{
    // TODO: add any language-specific constructs like "using", etc
    Stream stream = Location.OpenRead();
    Load(stream); // don't need to buffer if loading from subclass
    stream.Close();
}
0 голосов
/ 24 января 2009

Для изображений я бы пошел с наследством. В части загрузки / сохранения я бы пошел с шаблоном разработки стратегии, чтобы каждое изображение могло иметь алгоритм загрузки и алгоритм сохранения. Таким образом, вы можете изменять как загрузку, так и процесс сохранения, и вам не нужно загружать и сохранять методы класса Image.

0 голосов
/ 24 января 2009

Я думаю, что создание подкласса самого изображения для сохранения / загрузки не является правильной идеей, поскольку у вас не будет экземпляра для вызова Load on. Также изображение в памяти совершенно не зависит от исходного формата - абсолютно возможно открыть jpg и затем сохранить его как png, например.

Я бы сделал это следующим образом:

Image

ImageFormat { Save(Image, Stream); Image Load(Stream); }
JpegFormat : ImageFormat {}
TiffFormat : ImageFormat {}

Теперь для местоположения вы просто предоставляете способ получить поток чтения и поток записи.

0 голосов
/ 24 января 2009

Реализуйте Save () в классе ImageBase, а не в производных классах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...