1

I have a program that receives files from clients and do some operations on files and save them on disk or won’t save them. For decoupling of jobs, I created an interface named IFileEditor. Every component that do something on file, should implement this interface:

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);
    }

Main method in this interface is EditFile that receives file contents and do operations, and maybe in last save the result on disk. Sample class that I wrote is that create a thumbnail from image that implements this interface:

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
       }
    }

I may have lots of components like ThumbnailCreator, for example zip content or anything else that do operation on content.

In main program I load every component by reflection. Implementation of loading them is not important, just know that copying ddl of component beside .exe of main program and if dll implements IFileEditor, I add that to list.

Main question is that, main application just receives files and pass them to components, and components do the jobs. If I want to pass the result of one component to another, what should I do?

Remember that components doesn't know each other and main program should not interfere in passing results.

I searched, and I think chain-of-responsibility design pattern will solve my question. I don’t know is that correct? If correct how to implement this? For example one component creates the thumbnail and pass the result to compress the thumbnail.

I wrote this part like this, that every developer can create a component and main program could be extendable.

Thanks for reading this large post. ;)

Reza Akraminejad
  • 1,412
  • 3
  • 24
  • 38

1 Answers1

0

Yes, the chain-of-responsibility pattern is what you could use to solve this design problem. You basically need to make sure that each processor knows the next processor in the chain and calls it and have some sort of runner that configures the processor chain once, starts the processing operation and collects the end result. There are many use cases for such a pattern, System.Net.Http.DelegatingHandler (http://msdn.microsoft.com/en-us/library/system.net.http.delegatinghandler(v=vs.110).aspx) works like this. Java ServletFilters are conceptually the same thing as well.

You could also just keep your processors in a collection, iterate that collection and apply each processor to your input by calling a specific method, i.e. EditFile in your example.

Update -- here's a naive implementaiton to illustrate what I mean (taken from 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);
    }
}

Please take into consideration that this is a just an illustration and I won't claim that this will scale to a production/real-world use case :-). Depending on what you really do, you might need to work on performance improvements, it might be quite handy to work with streams instead of byte/char arrays for example.

PermaFrost
  • 1,386
  • 12
  • 10
  • So. I have a list of IFileEditor in my main program. you mean I should another class that manages components and add a field to IFileEditor interface that points to next components? Is writing a manager like this solve the problem? – Reza Akraminejad Jul 12 '14 at 10:31
  • You either make it so that every `IFileEditor` knows the next `IFileEditor` and then just keep a reference to the first `IFileEditor` and call the `EditFile` method on this first editor (which then has to call the next `IFileEditor` that is stored in a `Next` property or something). Another way you could do it would be to store a `List` and iterate over this list while calling each `IFileEditor` with the output of the previous `IFileEditor`. – PermaFrost Jul 12 '14 at 10:39
  • thanks, if I want to add this feature should I use another Interface inherits from IFileEditor or do it in the same interface? I've read in stack forums that should some jobs like these, mixing chain of responsibility pattern beside decorator pattern – Reza Akraminejad Jul 12 '14 at 10:49
  • I've added some code above to illustrate what I mean. Regarding *another interface*: I'm not sure, if you go for the *chain approach* it could be useful to have an abstract class that handles the `if (Next != null) Next.Edit(data);` stuff but apart from that I don't see any use unless your real code is more complex. – PermaFrost Jul 12 '14 at 10:52
  • I have another question too. what if I want to develop a component that receives list of file instead of one file? – Reza Akraminejad Jul 15 '14 at 05:42
  • It depends on your use case I would say. If you want the next `IFileEditor` to only start processing once the entire list of files was processed by the previous `IFileEditor`, then you could simply change the signature of the `Edit` method. If you just want to process many files, keep it like this and add a file loading facility that gets the files and passes them into the `IFileEditor` chain - you could even parallelize that process but you'd have to take care of/think about multi-threading concerns in that case. – PermaFrost Jul 17 '14 at 09:38