[英]Factory design pattern woes
所以我有这个工厂类,我认为它应该是一个静态工厂类应该是:
public class FileFactory
{
public static File Create(IObjectService service, string destination, string fileName, string mimeType)
{
var type = mimeType.ToLower().Split('/')[0];
switch(type)
{
case "image":
return new Image(service, destination, fileName);
case "document":
return new Document(service, destination, fileName);
default:
return new Document(service, destination, fileName);
}
}
}
现在,我有另一个不是静态的类,而且复杂得多:
public class MetadataFactory
{
public string destination;
public string fileName;
public string fullPath;
private XDocument document;
private XNamespace SystemNamespace = "http://ns.exiftool.ca/File/System/1.0/";
private XNamespace FileNamespace = "http://ns.exiftool.ca/File/1.0/";
private XNamespace Composite = "http://ns.exiftool.ca/Composite/1.0/";
private XNamespace PNG = "http://ns.exiftool.ca/PNG/PNG/1.0/";
private XNamespace GIF = "http://ns.exiftool.ca/GIF/GIF/1.0/";
private XNamespace IFD0 = "http://ns.exiftool.ca/EXIF/IFD0/1.0/";
private XNamespace IFD1 = "http://ns.exiftool.ca/EXIF/IFD1/1.0/";
private XNamespace BMP = "http://ns.exiftool.ca/BMP/BMP/1.0/";
private XNamespace JFIF = "http://ns.exiftool.ca/JFIF/JFIF/1.0/";
private XNamespace XMPtiff = "http://ns.exiftool.ca/XMP/XMP-tiff/1.0/";
private XNamespace XMPxmp = "http://ns.exiftool.ca/XMP/XMP-xmp/1.0/";
private XNamespace PDF = "http://ns.exiftool.ca/PDF/PDF/1.0/";
private XNamespace FlashPix = "http://ns.exiftool.ca/FlashPix/FlashPix/1.0/";
private XNamespace XML = "http://ns.exiftool.ca/XML/XML/1.0/";
public Metadata Create(string destination, string fileName, string exifToolPath)
{
this.destination = destination;
this.fileName = fileName;
this.fullPath = Path.Combine(destination, fileName);
this.document = new XDocument(GetFullXml(exifToolPath));
var mime = (string)this.document.Descendants(FileNamespace + "MIMEType").FirstOrDefault();
var type = mime.ToLower().Split('/')[0];
var metadata = new Metadata()
{
ReferenceId = this.GenerateId(),
FileSize = (string)this.document.Descendants(SystemNamespace + "FileSize").FirstOrDefault(),
FileType = (string)this.document.Descendants(FileNamespace + "FileType").FirstOrDefault(),
MIMEType = (string)this.document.Descendants(FileNamespace + "MIMEType").FirstOrDefault(),
};
switch (type)
{
case "image":
metadata.CreateDate = this.GetCreateDate();
metadata.ModifyDate = this.GetModifyDate();
metadata.ImageWidth = this.GetImageWidth();
metadata.ImageHeight = this.GetImageHeight();
metadata.ImageSize = this.GetImageSize();
metadata.Orientation = (string)this.document.Descendants(XMPtiff + "Orientation").FirstOrDefault();
break;
case "document":
metadata.CreateDate = this.GetCreateDate();
metadata.ModifyDate = this.GetModifyDate();
break;
}
return metadata;
}
private XElement GetFullXml(string exifToolPath)
{
string args = string.Format("-X \"{0}\"", this.fullPath);
string output = RunProcess(exifToolPath, args);
output = Sanitize(output);
return new XElement("FullMetadata", XElement.Parse(output));
}
private virtual string GetCreateDate()
{
if (this.document.Descendants(XMPxmp + "CreateDate").FirstOrDefault() != null)
return (string)this.document.Descendants(XMPxmp + "CreateDate").FirstOrDefault();
if (this.document.Descendants(PDF + "CreateDate").FirstOrDefault() != null)
return (string)this.document.Descendants(PDF + "CreateDate").FirstOrDefault();
if (this.document.Descendants(XMPxmp + "CreateDate").FirstOrDefault() != null)
return (string)this.document.Descendants(XMPxmp + "CreateDate").FirstOrDefault();
if (this.document.Descendants(FlashPix + "CreateDate").FirstOrDefault() != null)
return (string)this.document.Descendants(FlashPix + "CreateDate").FirstOrDefault();
if (this.document.Descendants(XML + "CreateDate").FirstOrDefault() != null)
return (string)this.document.Descendants(XML + "CreateDate").FirstOrDefault();
if (this.document.Descendants(Composite + "DateTimeCreated").FirstOrDefault() != null)
return (string)this.document.Descendants(Composite + "DateTimeCreated").FirstOrDefault();
return null;
}
private virtual string GetModifyDate()
{
if (this.document.Descendants(IFD0 + "ModifyDate").FirstOrDefault() != null)
return (string)this.document.Descendants(IFD0 + "ModifyDate").FirstOrDefault();
if (this.document.Descendants(XMPxmp + "ModifyDate").FirstOrDefault() != null)
return (string)this.document.Descendants(XMPxmp + "ModifyDate").FirstOrDefault();
if (this.document.Descendants(PDF + "ModifyDate").FirstOrDefault() != null)
return (string)this.document.Descendants(PDF + "ModifyDate").FirstOrDefault();
if (this.document.Descendants(XMPxmp + "ModifyDate").FirstOrDefault() != null)
return (string)this.document.Descendants(XMPxmp + "ModifyDate").FirstOrDefault();
if (this.document.Descendants(FlashPix + "ModifyDate").FirstOrDefault() != null)
return (string)this.document.Descendants(FlashPix + "ModifyDate").FirstOrDefault();
if (this.document.Descendants(XML + "ModifyDate").FirstOrDefault() != null)
return (string)this.document.Descendants(XML + "ModifyDate").FirstOrDefault();
return null;
}
private virtual string GetDuration()
{
if (this.document.Descendants(Composite + "Duration").FirstOrDefault() != null)
return (string)this.document.Descendants(Composite + "Duration").FirstOrDefault();
return null;
}
private virtual int GetImageWidth()
{
if (this.document.Descendants(PNG + "ImageWidth").FirstOrDefault() != null)
return (int)this.document.Descendants(PNG + "ImageWidth").FirstOrDefault();
if (this.document.Descendants(GIF + "ImageWidth").FirstOrDefault() != null)
return (int)this.document.Descendants(GIF + "ImageWidth").FirstOrDefault();
if (this.document.Descendants(IFD0 + "ImageWidth").FirstOrDefault() != null)
return (int)this.document.Descendants(IFD0 + "ImageWidth").FirstOrDefault();
if (this.document.Descendants(BMP + "ImageWidth").FirstOrDefault() != null)
return (int)this.document.Descendants(BMP + "ImageWidth").FirstOrDefault();
if (this.document.Descendants(FileNamespace + "ImageWidth").FirstOrDefault() != null)
return (int)this.document.Descendants(FileNamespace + "ImageWidth").FirstOrDefault();
return 0;
}
private virtual int GetImageHeight()
{
if (this.document.Descendants(PNG + "ImageHeight").FirstOrDefault() != null)
return (int)this.document.Descendants(PNG + "ImageHeight").FirstOrDefault();
if (this.document.Descendants(GIF + "ImageHeight").FirstOrDefault() != null)
return (int)this.document.Descendants(GIF + "ImageHeight").FirstOrDefault();
if (this.document.Descendants(IFD0 + "ImageHeight").FirstOrDefault() != null)
return (int)this.document.Descendants(IFD0 + "ImageHeight").FirstOrDefault();
if (this.document.Descendants(BMP + "ImageHeight").FirstOrDefault() != null)
return (int)this.document.Descendants(BMP + "ImageHeight").FirstOrDefault();
if (this.document.Descendants(FileNamespace + "ImageHeight").FirstOrDefault() != null)
return (int)this.document.Descendants(FileNamespace + "ImageHeight").FirstOrDefault();
return 0;
}
private virtual string GetImageSize()
{
if (this.document.Descendants(PNG + "ImageSize").FirstOrDefault() != null)
return (string)this.document.Descendants(PNG + "ImageSize").FirstOrDefault();
if (this.document.Descendants(GIF + "ImageSize").FirstOrDefault() != null)
return (string)this.document.Descendants(GIF + "ImageSize").FirstOrDefault();
if (this.document.Descendants(IFD0 + "ImageSize").FirstOrDefault() != null)
return (string)this.document.Descendants(IFD0 + "ImageSize").FirstOrDefault();
if (this.document.Descendants(BMP + "ImageSize").FirstOrDefault() != null)
return (string)this.document.Descendants(BMP + "ImageSize").FirstOrDefault();
if (this.document.Descendants(Composite + "ImageSize").FirstOrDefault() != null)
return (string)this.document.Descendants(Composite + "ImageSize").FirstOrDefault();
return null;
}
private string GenerateId()
{
long i = 1;
foreach (byte b in Guid.NewGuid().ToByteArray())
{
i *= ((int)b + 1);
}
return string.Format("{0:x}", i - DateTime.Now.Ticks);
}
private string RunProcess(string exifToolPath, string args)
{
if (String.IsNullOrEmpty(exifToolPath))
throw new SystemException("EXIFTool Executable Path Not Configured");
if (!System.IO.File.Exists(exifToolPath))
throw new SystemException("EXIFTool Executable Not Found: " + exifToolPath);
var process = new Process
{
StartInfo =
{
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
FileName = exifToolPath,
Arguments = args
}
};
process.Start();
var output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
return output;
}
private string Sanitize(string s)
{
return s.Replace("&", string.Empty);
}
}
我把这两个工厂称为:
var metadata = new MetadataFactory().Create(this.uploadPath, asset.FileName, this.exifToolPath);
var file = FileFactory.Create(objectService, this.uploadPath, asset.FileName, metadata.MIMEType);
现在,问题是这个。 FileFactory返回从File继承的Document或Image 。 对我来说,这是建造工厂的正确方法。
MetadataFactory,另一方面只返回元数据 ,它只能通过使用的Exif文件解压得到它的元数据。 所以,我的问题是:工厂是否是正确的模式,或者我应该考虑做其他事情?
只是为了澄清一些事情。
元数据是POCO类元数据只能通过运行使用Exif提取xml数据的进程来构建
如果可以,请你帮助我 :)
所以我有这个工厂类,我相信它应该是一个静态工厂类
没有这样的模式。 只有“工厂方法”和“抽象工厂”。 您可能有一个具有静态工厂方法的类,但不具有静态工厂类。
第二类在概念上更像是Builder而不是Factory方法。 工厂应该是简单的方法,只有一个目的 - 根据提供的批准返回一个对象。 构建器更适合构建复杂对象。
所以,我采用了Builder Design Pattern (由Ondrej建议)并将其应用于我的元数据。 这就是它的方式。
首先,我创建了我的IMetadataBuilder接口:
interface IMetadataBuilder
{
void SetCreateDate();
void SetModifyDate();
void SetImageWidth();
void SetImageHeight();
void SetImageSize();
Metadata GetMetadata();
}
非常直接,然后从那里我创建了我的DocumentMetadataBuilder和ImageMetadataBuilder,如下所示:
public class DocumentMetadataBuilder : IMetadataBuilder
{
private readonly Metadata metadata;
private readonly XDocument document;
private XNamespace Composite = "http://ns.exiftool.ca/Composite/1.0/";
private XNamespace XMPxmp = "http://ns.exiftool.ca/XMP/XMP-xmp/1.0/";
private XNamespace PDF = "http://ns.exiftool.ca/PDF/PDF/1.0/";
private XNamespace FlashPix = "http://ns.exiftool.ca/FlashPix/FlashPix/1.0/";
private XNamespace XML = "http://ns.exiftool.ca/XML/XML/1.0/";
public DocumentMetadataBuilder(XDocument document, string fileSize, string fileType, string mimeType)
{
this.document = document;
this.metadata = new Metadata()
{
FileSize = fileSize,
FileType = fileType,
MIMEType = mimeType
};
}
public void SetCreateDate()
{
var createDate = string.Empty;
if (this.document.Descendants(PDF + "CreateDate").FirstOrDefault() != null)
createDate = (string)this.document.Descendants(PDF + "CreateDate").FirstOrDefault();
if (this.document.Descendants(XMPxmp + "CreateDate").FirstOrDefault() != null)
createDate = (string)this.document.Descendants(XMPxmp + "CreateDate").FirstOrDefault();
if (this.document.Descendants(FlashPix + "CreateDate").FirstOrDefault() != null)
createDate = (string)this.document.Descendants(FlashPix + "CreateDate").FirstOrDefault();
if (this.document.Descendants(XML + "CreateDate").FirstOrDefault() != null)
createDate = (string)this.document.Descendants(XML + "CreateDate").FirstOrDefault();
if (this.document.Descendants(Composite + "DateTimeCreated").FirstOrDefault() != null)
createDate = (string)this.document.Descendants(Composite + "DateTimeCreated").FirstOrDefault();
this.metadata.CreateDate = createDate;
}
public void SetModifyDate()
{
var modifyDate = string.Empty;
if (this.document.Descendants(PDF + "ModifyDate").FirstOrDefault() != null)
modifyDate = (string)this.document.Descendants(PDF + "ModifyDate").FirstOrDefault();
if (this.document.Descendants(XMPxmp + "ModifyDate").FirstOrDefault() != null)
modifyDate = (string)this.document.Descendants(XMPxmp + "ModifyDate").FirstOrDefault();
if (this.document.Descendants(FlashPix + "ModifyDate").FirstOrDefault() != null)
modifyDate = (string)this.document.Descendants(FlashPix + "ModifyDate").FirstOrDefault();
if (this.document.Descendants(XML + "ModifyDate").FirstOrDefault() != null)
modifyDate = (string)this.document.Descendants(XML + "ModifyDate").FirstOrDefault();
this.metadata.ModifyDate = modifyDate;
}
public void SetImageWidth()
{
throw new NotImplementedException();
}
public void SetImageHeight()
{
throw new NotImplementedException();
}
public void SetImageSize()
{
throw new NotImplementedException();
}
public Metadata GetMetadata()
{
throw new NotImplementedException();
}
}
和
public class ImageMetadataBuilder : IMetadataBuilder
{
private readonly Metadata metadata;
private readonly XDocument document;
private XNamespace SystemNamespace = "http://ns.exiftool.ca/File/System/1.0/";
private XNamespace FileNamespace = "http://ns.exiftool.ca/File/1.0/";
private XNamespace Composite = "http://ns.exiftool.ca/Composite/1.0/";
private XNamespace PNG = "http://ns.exiftool.ca/PNG/PNG/1.0/";
private XNamespace GIF = "http://ns.exiftool.ca/GIF/GIF/1.0/";
private XNamespace IFD0 = "http://ns.exiftool.ca/EXIF/IFD0/1.0/";
private XNamespace IFD1 = "http://ns.exiftool.ca/EXIF/IFD1/1.0/";
private XNamespace BMP = "http://ns.exiftool.ca/BMP/BMP/1.0/";
private XNamespace JFIF = "http://ns.exiftool.ca/JFIF/JFIF/1.0/";
private XNamespace XMPtiff = "http://ns.exiftool.ca/XMP/XMP-tiff/1.0/";
private XNamespace XMPxmp = "http://ns.exiftool.ca/XMP/XMP-xmp/1.0/";
private XNamespace PDF = "http://ns.exiftool.ca/PDF/PDF/1.0/";
private XNamespace FlashPix = "http://ns.exiftool.ca/FlashPix/FlashPix/1.0/";
private XNamespace XML = "http://ns.exiftool.ca/XML/XML/1.0/";
public ImageMetadataBuilder(XDocument document, string fileSize, string fileType, string mimeType)
{
this.document = document;
this.metadata = new Metadata() {
FileSize = fileSize,
FileType = fileType,
MIMEType = mimeType
};
}
public void SetCreateDate()
{
var createDate = string.Empty;
if (this.document.Descendants(XMPxmp + "CreateDate").FirstOrDefault() != null)
createDate = (string)this.document.Descendants(XMPxmp + "CreateDate").FirstOrDefault();
if (this.document.Descendants(Composite + "DateTimeCreated").FirstOrDefault() != null)
createDate = (string)this.document.Descendants(Composite + "DateTimeCreated").FirstOrDefault();
this.metadata.CreateDate = createDate;
}
public void SetModifyDate()
{
var modifyDate = string.Empty;
if (this.document.Descendants(IFD0 + "ModifyDate").FirstOrDefault() != null)
modifyDate = (string)this.document.Descendants(IFD0 + "ModifyDate").FirstOrDefault();
if (this.document.Descendants(XMPxmp + "ModifyDate").FirstOrDefault() != null)
modifyDate = (string)this.document.Descendants(XMPxmp + "ModifyDate").FirstOrDefault();
this.metadata.ModifyDate = modifyDate;
}
public void SetImageWidth()
{
var imageWidth = 0;
if (this.document.Descendants(PNG + "ImageWidth").FirstOrDefault() != null)
imageWidth = (int)this.document.Descendants(PNG + "ImageWidth").FirstOrDefault();
if (this.document.Descendants(GIF + "ImageWidth").FirstOrDefault() != null)
imageWidth = (int)this.document.Descendants(GIF + "ImageWidth").FirstOrDefault();
if (this.document.Descendants(IFD0 + "ImageWidth").FirstOrDefault() != null)
imageWidth = (int)this.document.Descendants(IFD0 + "ImageWidth").FirstOrDefault();
if (this.document.Descendants(BMP + "ImageWidth").FirstOrDefault() != null)
imageWidth = (int)this.document.Descendants(BMP + "ImageWidth").FirstOrDefault();
if (this.document.Descendants(FileNamespace + "ImageWidth").FirstOrDefault() != null)
imageWidth = (int)this.document.Descendants(FileNamespace + "ImageWidth").FirstOrDefault();
this.metadata.ImageWidth = imageWidth;
}
public void SetImageHeight()
{
var imageHeight = 0;
if (this.document.Descendants(PNG + "ImageHeight").FirstOrDefault() != null)
imageHeight = (int)this.document.Descendants(PNG + "ImageHeight").FirstOrDefault();
if (this.document.Descendants(GIF + "ImageHeight").FirstOrDefault() != null)
imageHeight = (int)this.document.Descendants(GIF + "ImageHeight").FirstOrDefault();
if (this.document.Descendants(IFD0 + "ImageHeight").FirstOrDefault() != null)
imageHeight = (int)this.document.Descendants(IFD0 + "ImageHeight").FirstOrDefault();
if (this.document.Descendants(BMP + "ImageHeight").FirstOrDefault() != null)
imageHeight = (int)this.document.Descendants(BMP + "ImageHeight").FirstOrDefault();
if (this.document.Descendants(FileNamespace + "ImageHeight").FirstOrDefault() != null)
imageHeight = (int)this.document.Descendants(FileNamespace + "ImageHeight").FirstOrDefault();
this.metadata.ImageHeight = imageHeight;
}
public void SetImageSize()
{
var imageSize = string.Empty;
if (this.document.Descendants(PNG + "ImageSize").FirstOrDefault() != null)
imageSize = (string)this.document.Descendants(PNG + "ImageSize").FirstOrDefault();
if (this.document.Descendants(GIF + "ImageSize").FirstOrDefault() != null)
imageSize = (string)this.document.Descendants(GIF + "ImageSize").FirstOrDefault();
if (this.document.Descendants(IFD0 + "ImageSize").FirstOrDefault() != null)
imageSize = (string)this.document.Descendants(IFD0 + "ImageSize").FirstOrDefault();
if (this.document.Descendants(BMP + "ImageSize").FirstOrDefault() != null)
imageSize = (string)this.document.Descendants(BMP + "ImageSize").FirstOrDefault();
if (this.document.Descendants(Composite + "ImageSize").FirstOrDefault() != null)
imageSize = (string)this.document.Descendants(Composite + "ImageSize").FirstOrDefault();
this.metadata.ImageSize = imageSize;
}
public Metadata GetMetadata()
{
return metadata;
}
}
我认为首先要注意的是这两个类的构造函数。 我传入一个XDocument(这是xml格式的元数据,但我也传入了fileSize,fileType和MimeType,我用它来创建我的Metadata实例。
在DocumentMetadataBuilder类中,即使我实现IMetadataBuilder,大多数方法实际上都会抛出NotImplementedException 。 这是有目的的,并在我的Director类中变得明显:
public class MetadataCreator
{
private XNamespace FileNamespace = "http://ns.exiftool.ca/File/1.0/";
private XNamespace SystemNamespace = "http://ns.exiftool.ca/File/System/1.0/";
private IMetadataBuilder builder;
public Metadata Create(string destination, string fileName, string exifToolPath)
{
var fullPath = Path.Combine(destination, fileName);
var document = new XDocument(GetFullXml(fullPath, exifToolPath));
var fileSize = (string)document.Descendants(SystemNamespace + "FileSize").FirstOrDefault();
var fileType = (string)document.Descendants(FileNamespace + "FileType").FirstOrDefault();
var mimeType = (string)document.Descendants(FileNamespace + "MIMEType").FirstOrDefault();
var type = mimeType.ToLower().Split('/')[0];
switch (type)
{
case "image":
builder = new ImageMetadataBuilder(document, fileSize, fileType, mimeType);
builder.SetCreateDate();
builder.SetModifyDate();
builder.SetImageWidth();
builder.SetImageHeight();
builder.SetImageSize();
break;
case "document":
builder = new DocumentMetadataBuilder(document, fileSize, fileType, mimeType);
builder.SetCreateDate();
builder.SetModifyDate();
break;
}
return builder.GetMetadata();
}
private XElement GetFullXml(string filePath, string exifToolPath)
{
string args = string.Format("-X \"{0}\"", filePath);
string output = RunProcess(exifToolPath, args);
output = Sanitize(output);
return new XElement("FullMetadata", XElement.Parse(output));
}
private string GenerateId()
{
long i = 1;
foreach (byte b in Guid.NewGuid().ToByteArray())
{
i *= ((int)b + 1);
}
return string.Format("{0:x}", i - DateTime.Now.Ticks);
}
private string RunProcess(string exifToolPath, string args)
{
if (String.IsNullOrEmpty(exifToolPath))
throw new SystemException("EXIFTool Executable Path Not Configured");
if (!System.IO.File.Exists(exifToolPath))
throw new SystemException("EXIFTool Executable Not Found: " + exifToolPath);
var process = new Process
{
StartInfo =
{
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
FileName = exifToolPath,
Arguments = args
}
};
process.Start();
var output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
return output;
}
private string Sanitize(string s)
{
return s.Replace("&", string.Empty);
}
}
现在,使用Director类,我决定将Get和Create结合到一个方法中,因为我不想调用Create方法然后每次都调用Get方法。 在调用Create时,我没有理由不返回Metadata类。
另一件需要注意的是,我基于IMetadataBuilder具体类调用了不同的方法。 ImageMetadataBuilder调用所有公共方法, DocumentMetadataBuilder只调用SetCreateDate和SetModifyDate 。
然后你可以看到我返回IMetadataBuilder * GetMetadata *方法。
这被称为:
var metadata = (asset.Metadata == null) ? new MetadataCreator().Create(this.uploadPath, asset.FileName, this.exifToolPath) : asset.Metadata;
除非我完全错过了这艘船,否则我相信这是Builder Design Pattern的一个很好的例子
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.