Frage

I am working on a application that uses a chain of responsibility to process a request. I know how to build the chain, but if you look at the example below, I would have to call link1.Process(request); to initiate the chain process. What I am trying to figure out is, is there a way to treat this like a collection can just call the first link of the chain, whatever that may be? The reason being is, I know what the base element is (the final default object), but other programmers could add objects into the chain and could potentially put them in a position where the chain would never get to them.

public class MergedFieldProcessor
{

    public MergedFieldProcessor()
    {
        //Define CoR here

       FieldProcessor link1 = new FieldProcessor();
       FieldProcessor link2 = new FieldProcessor();
       FieldProcessor link3 = new FieldProcessor();

       link1.SetNextProcessor(link2);
       link2.SetNextProcessor(link3);

    }



}

public abstract class FieldProcessor
{
    private FieldProcessor NextProcessor { get; set; }

    public FieldProcessor()
    {
        this.NextProcessor = new SprocObject();
    }

    public void SetNext (FieldProcessor successor)
    {
       this.NextProcessor = successor;
    }

    //determines if this link in the change is responsible for the request
    public abstract Boolean WillProcess(MergedFieldProcessorRequest request);

    //performs the processing required for the tag
    public abstract void ProcessField(MergedFieldProcessorRequest request);


    //chain method that passes the request
    public void ProcessRequest(MergedFieldProcessorRequest request)
    {
        if (!this.WillProcess(request))
            this.NextProcessor.ProcessRequest(request);
        else
            this.ProcessField(request);
    }


}

public class MergedFieldProcessorRequest
{
    public MergedField Field { get; set; }

    public Dictionary<string, string> SearchParams { get; set; }
}

Example of unreachable links:

FieldProcessor link1 = new FieldProcessor();
        FieldProcessor link2 = new FieldProcessor();
        FieldProcessor link3 = new FieldProcessor();
        FieldProcessor link4 = new FieldProcessor();

        link4.SetNext(link1);
        link1.SetNext(link2);
        link2.SetNext(link3);

if they didn't modify the code where the process is initated to say link4.Process(request), then link4 would never be a part of the chain.

In short, is it possible to dynamically build the chain so that if someone adds the object to the collection, it automatically gets added into the chain?

War es hilfreich?

Lösung 2

Here is the solution I came up with. Just add each processor to a collection and then iterate over that collection to build the chain, and to process the chain, simply call this.Links[0].Process(request);

 #region Build Chain Collection;
        this.Links = new List<FieldProcessor>()
        {
            new StudentEnrollmentDetailsProcessor(),
            new SprocObject()
        };
        #endregion; 

        #region Build Chain Dynamically
        for (int i = 0; i < this.Links.Count(); i++)
        {
            if (i < this.Links.Count())
            {
                this.Links[i].SetNext(this.Links[i + 1]);
            }
        }
        #endregion;

Andere Tipps

Do you want to give users ability to build chains... without ability to build chains?
Either user is responsible for chaining objects, or throw the chaining away and provide any collection for FieldProcessors (then call them in order they're in collection).

If the chaining is important, the best you can do is a chain validation for cycles and unreachable links before processing.

you could use reflection and a bit of recursion

public class MergedFieldProcessor
{
    private FieldProcessor first;

    private FieldProcessor CreateLink(IEnumerator<Type> processors)
    {
        if(processors.MoveNext())
        {
            FieldProcessor link = (FieldProcessor)Activator.CreateInstance(processors.Current);
            link.NextProcessor = CreateLink(processors);
            return link;
        }
        return null;
    }

    public MergedFieldProcessor()
    {
        var processType = typeof(FieldProcessor);
        var allProcess = processType.Assembly.GetTypes()
            .Where(t => t != processType && processType.IsAssignableFrom(t));
        first = CreateLink(allProcess.GetEnumerator());
    }

    public void Handle(MergedFieldProcessorRequest request)
    {
        first.ProcessRequest(request);
    }
}

this will ensure that all possible links are created and chained together, but with a caveat: the last link will have a null successor and generally it must be a chain closer (will handle whatever request).

public abstract class AbCommon
{
    public virtual AbCommon Successor { get; protected set; }

    public virtual void Execute()
    {           
        if (Successor != null)
        {
            Successor.Execute();
        }
    }

    public virtual void SetSuccessor(AbCommon successor)
    {
        if (Successor != null)
        {
            Successor.SetSuccessor(successor);
        }
        else
        {
            this.Successor = successor;
        }
    }
}

class DefaultClass : AbCommon
{   
    public override void Execute()
    {
        Console.WriteLine("DC");
        base.Execute();
    }       
}

class FirstClass: AbCommon
{
    public override void Execute()
    {
        Console.WriteLine("FC");
        base.Execute();
    }
}

class SecondClass: AbCommon
{   
    public override void Execute()
    {
        Console.WriteLine("SC");
        base.Execute();
    }
}

class ThirdClass: AbCommon
{
    public override void Execute()
    {
        Console.WriteLine("TC");
        base.Execute();
    }
}

And use these as

 class Program
  {
    static void Main(string[] args)
    {
        DefaultClass dc = new DefaultClass();

            FirstClass fc = new FirstClass();
            dc.SetSuccessor(fc);

            SecondClass sc = new SecondClass();
            dc.SetSuccessor(sc);

            ThirdClass tc = new ThirdClass();
            dc.SetSuccessor(tc);

            dc.Execute();
}}

You can add or remove object dynamically

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top