1

我有一个程序从客户端接收文件并对文件进行一些操作并将它们保存在磁盘上或不保存它们。为了解耦工作,我创建了一个名为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,我将其添加到列表中。

主要问题是,主应用程序只是接收文件并将它们传递给组件,组件完成工作。如果我想将一个组件的结果传递给另一个组件,我应该怎么做?

请记住,组件彼此不知道,主程序不应干扰传递结果。

我搜索了,我认为责任链设计模式将解决我的问题。不知道这样对吗?如果正确,如何实施?例如,一个组件创建缩略图并将结果传递给压缩缩略图。

我是这样写这部分的,每个开发人员都可以创建一个组件,并且主程序可以是可扩展的。

感谢您阅读这篇大文章。;)

4

1 回答 1

0

是的,您可以使用责任链模式来解决这个设计问题。您基本上需要确保每个处理器都知道链中的下一个处理器并调用它,并且有某种运行器来配置处理器链一次,开始处理操作并收集最终结果。这种模式有很多用例,System.Net.Http.DelegatingHandlerhttp://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);
    }
}

请考虑到这只是一个说明,我不会声称这将扩展到生产/实际用例:-)。根据您的实际操作,您可能需要改进性能,例如使用流而不是字节/字符数组可能会非常方便。

于 2014-07-12T10:24:58.240 回答