我需要以各种格式保存图像文件。 格式列表可能会经常更改,因此我希望保存可以非常可扩展。 此外,保存可以在许多地方进行(硬盘,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。
答案 0 :(得分:5)
首先,我会在你的Image上实现流。这样,您可以从流中创建构造函数,以及为任何“图像”子类创建流的方法。
此外,我会创建您的“保存”基础架构,以简单地接受流并将其写入适当的技术(ftp,文件等)。
这样你最终得到可扩展的图像(如果你可以获得一个流,你可以做很多很多事情),你最终得到一个可扩展的保存基础设施(任何可以转到流的东西都可以被保存)
编辑:就个人而言,数据类型对象的保存方法听起来像是在错误的地方,但不知道整个系统我不能肯定地说。只是我的2c。
答案 1 :(得分:1)
在我看来,具体的课程应该只处理原始数据;这可能是写一个本地文件(然后由基本代码处理),或者是一个流。
例如,可能是:
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();
}
答案 2 :(得分:1)
我的方式略有不同。 (语法是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. */
}
}
从Web服务器的内容类型到Image类的映射也可能在Location基类(或完全不同的帮助器类)中以更可重用的方式发生,但这就是我将如何进行的。
答案 3 :(得分:0)
在ImageBase类中实现Save(),而不是在派生类中实现。
答案 4 :(得分:0)
我认为将图像本身子类化为保存/加载不是一个正确的想法,因为你没有实例来调用Load on。内存中的图像也完全独立于原始格式 - 例如,打开jpg然后将其另存为png是绝对可能的。
我会按以下方式进行:
Image
ImageFormat { Save(Image, Stream); Image Load(Stream); }
JpegFormat : ImageFormat {}
TiffFormat : ImageFormat {}
现在,您只需提供一种获取阅读流和写作流的方法。
答案 5 :(得分:0)
对于图像,我会继承。对于加载/保存部分,我将使用策略设计模式,以便每个图像都可以具有LoadingAlgorithm和SavingAlgorithm。这样您就可以改变加载和保存过程,而不必进行Image类的加载和保存方法。