我有一个程序从客户端接收文件并对文件执行某些操作并将它们保存在磁盘上或不保存它们。
为了解耦作业,我创建了一个名为IFileEditor
的接口。在文件上执行某些操作的每个组件都应该实现此接口:
public interface IFileEditor
{
string Name { get; set; }
byte[] Content { get; set; }
string EditedName { get; set; }
byte[] EditedConent { get; set; }
string ComponentName { get; }
XmlDocument Config { get; set; }
XmlDocument Result { get; set; }
void EditFile(byte[] content);
}
此接口中的主要方法是EditFile,它接收文件内容并执行操作,最后可能将结果保存在磁盘上。 我写的示例类是从实现此接口的图像创建缩略图:
public class ThumbnailCreator : IFileEditor
{
public string Name { get; set; }
public byte[] Content { get; set; }
public sting EditedName { get; set; }
public byte[] EditedConent { get; set; }
public XmlDocument Config { get; set; }
public XmlDocument Result { get; set; }
public void EditFile(byte[] content)
{
//change the file content and save the thumbnail content in disk
}
}
我可能有许多组件,例如ThumbnailCreator,例如zip内容或其他对内容进行操作的内容。
在主程序中,我通过反射加载每个组件。加载它们的实现并不重要,只要知道在主程序的.exe旁边复制组件的ddl,如果dll实现了IFileEditor,我就把它添加到列表中。
主要问题是,主应用程序只接收文件并将它们传递给组件,组件执行作业。如果我想将一个组件的结果传递给另一个组件,我该怎么办?
请记住,组件彼此之间并不了解,主程序不应干扰传递结果。
我搜索过,我认为责任链设计模式将解决我的问题。我不知道那是对的吗?如果正确如何实现呢? 例如,一个组件创建缩略图并传递结果以压缩缩略图。
我这样编写了这个部分,每个开发人员都可以创建一个组件,主程序可以扩展。
感谢您阅读这篇大文章。 ;)
答案 0 :(得分:0)
是的,责任链模式是您可以用来解决此设计问题的方法。您基本上需要确保每个处理器都知道链中的下一个处理器并调用它并使用某种类型的运行器来配置处理器链一次,启动处理操作并收集最终结果。这种模式有很多用例,System.Net.Http.DelegatingHandler
(http://msdn.microsoft.com/en-us/library/system.net.http.delegatinghandler(v=vs.110).aspx)就是这样的。 Java ServletFilters在概念上也是一样的。
您也可以将处理器放在一个集合中,迭代该集合并通过调用特定方法将每个处理器应用于您的输入,例如您的示例中的EditFile
。
更新 - 这是一个天真的实现来说明我的意思(取自LINQPad):
void Main()
{
// Variant 1 - Chaining
var editorChain = new UpperCaseFileEditor(new LowerCaseFileEditor());
var data1 = new char[] { 'a', 'B', 'c' };
editorChain.Edit(data1);
data1.Dump(); // produces ['a','b','c']
// Variant 2 - Iteration
var editors = new List<IFileEditor> { new LowerCaseFileEditor(), new UpperCaseFileEditor() };
var data2 = new char[] { 'a', 'B', 'c' };
foreach (var e in editors) {
e.Edit(data2);
}
data2.Dump(); // produces ['A','B','C']
}
// Define other methods and classes here
public interface IFileEditor {
IFileEditor Next { get; set; }
void Edit(char[] data);
}
public class UpperCaseFileEditor : IFileEditor {
public IFileEditor Next { get; set; }
public UpperCaseFileEditor() : this(null) {}
public UpperCaseFileEditor(IFileEditor next) {
Next = next;
}
public void Edit(char[] data) {
for (int i = 0; i < data.Length; ++i) {
data[i] = Char.ToUpper(data[i]);
}
if (Next != null)
Next.Edit(data);
}
}
public class LowerCaseFileEditor : IFileEditor {
public IFileEditor Next { get; set; }
public LowerCaseFileEditor() : this(null) {}
public LowerCaseFileEditor(IFileEditor next) {
Next = next;
}
public void Edit(char[] data) {
for (int i = 0; i < data.Length; ++i) {
data[i] = Char.ToLower(data[i]);
}
if (Next != null)
Next.Edit(data);
}
}
请注意,这仅仅是一个例子,我不会声称这将扩展到生产/现实世界的用例:-)。根据您的实际操作,您可能需要进行性能改进,例如,使用流而不是byte / char数组可能非常方便。