简体   繁体   中英

decoupled components passing result c#

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

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, ie 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM