Which design of the creation template meets these requirements?

I have a scenario in which I pass the request object "request" to the service, and the service itself must create several different "processors" depending on the data in the request.

Each processor can be one of several different types. So, for example, a crude ugly implementation might look like this:

public Collection<IProcessor> UglyCreationalMethod(Request request) { var processors = new Collection<IProcessor>(); if(request.Type == RequestType.SomeVal) { if(request.Id > 1000) { processors.Add(new ProcessLargeRequest(request)); } else { processors.Add(new ProcessSmallRequest(request)); } } else (request.Type == RequestType.SomeOtherVal) { if(request.Source == RequestSource.User) { processors.Add(new ProcessUserRequest(request)); } else { processors.Add(new ProcessCorpRequest(request)); } } if(request.SomeProp == "blah") processors.Add(new ProcessBlahRequest(request)); // ... etc ad infinitum :) return processors; } 

I am looking for a template that expands and hides unpleasant logic that determines the types of processors that the service needs to create, so it’s a little clean and easy to maintain than the ugly code mentioned above.

I know about factory methods, but they are not enough.

Suggestions appreciated.

+4
source share
3 answers

What you want to do is create a Factory, the main question is how to set it up. I like to follow the approach when the choice of a method should be created within the scope of Factory responsibilities, and not in the classes that are created - this leads to a better configuration and simplifies management.

I would create something like this:

  public struct ProcessorCreationSettings { public Predicate<Request> Predicate; public Func<Request, IProcessor> Creator; } public class ProcessorFactory { protected static List<ProcessorCreationSettings> settings = new List<ProcessorCreationSettings>(); static ProcessorFactory() { settings.Add(new ProcessorCreationSettings { Predicate = r => r.Type == RequestType.SomeOther && r.Id > 1000, Creator = r => new ProcessLargeRequest(r) }); settings.Add(new ProcessorCreationSettings { Predicate = r => r.Type == RequestType.SomeOther && r.Id <= 1000, Creator = r => new ProcessSmallRequest(r) }); } public List<IProcessor> Create(Request request) { return settings .Where(s => s.Predicate(request)) .Select(s => s.Creator(request)) .ToList(); } } 

Part of the configuration is done using a static list, however you can also use an IoC container for this if it has such a function.

+1
source

One template that comes to mind is the Chain of Responsibility (perhaps not a creation template)

First, you need RequestHandlers

 public interface IRequestHandler { bool CanHandle(Request req); void Handle(Request req); } public class LargeRequestHandler : IRequestHandler { public bool CanHandle(Request req) { return (req.Type == RequestType.SomeVal && req.id > 1000); } public void Handle(Request req) { processors.Add(new ProcessLargeRequest(request)); } } public class SmallRequestHandler : IRequestHandler { public bool CanHandle(Request req) { return (req.Type == RequestType.SomeVal && req.id < 1000); } public void Handle(Request req) { processors.Add(new SmallLargeRequest(request)); } } 

... similarly, continue to add classes for more handlers as needed.

Then chain these handlers, for example

 public class RequestChain { IRequestHandler[] handlers; public RequestChain() { handlers = new[] { new LargeRequestHandler(), new SmallRequestHandler() }; } public void ProcessRequest(Request req) { foreach (var handler in handlers) { if (handler.CanHandle(req)) { handler.Handle(req); } } } } 

Hope this helps. Greetings.

+2
source

A factory is probably the right way, but you need a little more, namely configuration.

For example, you might need a configuration file that looks something like this:

 <processor type="typename"> <rules> <rule type="requestIdThresholdRule"> <configuration evaluationType="ExceedsThreshold" threshold="1000"/> </rule> </rules> </processor> <processor type="othertypename"> <rules> <rule type="yadda"> <configuration evaluationType="DoesNotMeetThreshold" threshold="1000"/> </rule> </rules> 

This allows you a lot of flexibility to determine which types are created based on the estimated runtime of the context. You do not have code loading sitting in the factory method itself, but in a few rules, which are mainly determined by configuration values. The code is much smaller, much more flexible.

Then you simply call it like this:

  List<ISomething> items = ISomethingFactory.CreateISomethingsForContext(context); 
+1
source

All Articles