Without entering in academic definitions, let's say that the Strategy Pattern is used when you have a client code (Context) which will execute an operation, and this operation could be implemented in different ways (algorithms). For instance: https://www.dofactory.com/net/strategy-design-pattern
Which Strategy (or algorithm) will be used depend on many occasions of some input conditions. That is why Strategy Pattern sometimes is used in combination with Factory Pattern. The Client pass the input conditions to the Factory. Then the Factory knows which Strategy has to create. Then the Client execute the operation of the Strategy created.
However, I have come across in several occasions with a problem that seems to me the opposite. The operation to be execute is always the same, but it would be only executed depending on a family of input conditions. For example:
public interface IStrategy
{
string FileType { get; }
bool CanProcess(string text);
}
public class HomeStrategy : IStrategy
{
public string FileType => ".txt";
public bool CanProcess(string text)
{
return text.Contains("house") || text.Contains("flat");
}
}
public class OfficeStrategy : IStrategy
{
public string FileType => ".doc";
public bool CanProcess(string text)
{
return text.Contains("office") || text.Contains("work") || text.Contains("metting");
}
}
public class StragetyFactory
{
private List<IStrategy> _strategies = new List<IStrategy>{ new HomeStrategy(), new OfficeStrategy() };
public IStrategy CreateStrategy(string fileType)
{
return _strategies.Single(s => s.FileType == fileType);
}
}
Now the client code will get the files from some repository and will save the files in the database. This is the operation, store the files in the database, just depending on the type of the file and the specific conditions for each file.
public class Client
{
public void Execute()
{
var files = repository.GetFilesFromDisk();
var factory = new StragetyFactory();
foreach (var file in files)
{
var strategy = factory.CreateStrategy(file.Type);
if (strategy.CanProcess(file.ContentText))
{
service.SaveInDatabase(file);
}
}
}
}
Am I wrong to believe that this is a different pattern than the Strategy Pattern? (even though I have called Strategy in the code above because I have seem it like this in several occasions)
If this problem is different than the one the Strategy Pattern solves, then which pattern is it?.
Not really a strategy pattern, because as definition in the strategy pattern in Wikipedia says:
In computer programming, the strategy pattern (also known as the
policy pattern) is a behavioral software design pattern that enables
selecting an algorithm at runtime. Instead of implementing a single
algorithm directly, code receives run-time instructions as to which in
a family of algorithms to use.[1]
You're not selecting an algorithm to execute at runtime, you just check conditions to see if file type satisfies conditions and then execute the algorithm.
Do you expect this to change ever ? Do you need this to be extensible, so that in the future if you need to execute different code based on file type you can do it easily.
If answer to those questions is yes, then you can keep strategies and apply few changes.
First define base strategy class that defines the code to execute
public abstract class StrategyBase
{
public abstract bool CanProcess(string fileType);
public virtual void Execute(File file)
{
_service.SaveInDatabase(file);
}
}
Your strategies change to derive from base
public class HomeStrategy : StrategyBase
{
public string FileType => ".txt";
public override bool CanProcess(string text)
{
return text.Contains("house") || text.Contains("flat");
}
}
// implement the same for the rest of strategies...
As mentioned in the comment, it's not really a factory as it doesn't create a new strategy on every call. It's more like a provider which provides strategy to execute based on file type.
public class StragetyProvider
{
private List<StrategyBase> _strategies = new List<StrategyBase>{ new HomeStrategy(), new OfficeStrategy() };
public StrategyBase GetStrategy(string fileType)
{
return _strategies.FirstOrDefault(s => s.CanProcess(fileType));
}
}
As a result client code became much simpler:
public class Client
{
public void Execute()
{
var files = repository.GetFilesFromDisk();
var provider = new StragetyProvider();
foreach (var file in files)
{
var strategy = provider.GetStrategy(file.Type);
strategy?.Execute(file);
}
}
}
Notice, when you need to add new condition, you just implement a new class that derives from StrategyBase and add it to the list of strategies in the provider and no other changes required. If you would need to execute different logic for some new file type, you will create new strategy and override Execute method and that's it.
If this does really look like an overkill and you don't need to ever extend this solution with new behavior & the only thing you want is to be able to add new condition then go with another approach.
public interface ISatisfyFileType
{
bool Satisfies(string fileType);
}
public class HomeCondition : ISatisfyFileType
{
public string FileType => ".txt";
public bool Satisfies(string text)
{
return text.Contains("house") || text.Contains("flat");
}
}
// the rest of conditions
Compose all conditions into one
public class FileConditions
{
private List<ISatisfyFileType> _conditions = new List<ISatisfyFileType>{ new HomeStrategy(), new OfficeStrategy() };
public bool Satisfies(string fileType) =>
_conditions.Any(condition => condition.Satisfies(fileType));
}
And the client:
public class Client
{
public void Execute()
{
var files = repository.GetFilesFromDisk();
var fileTypeConditions = new FileConditions();
foreach (var file in files)
{
if (fileTypeConditions.Satisfies(file.ContentText))
{
service.SaveInDatabase(file);
}
}
}
}
This also has the benefit of implementing a new condition and adding it to FileConditions class should you need a new condition without touching client code.
Related
Consider the following code:
public interface IFileBackup
{
Task Backup(byte[] file);
}
public class BackUpMechanismA : IFileBackup
{
//Implementation
public async Task Backup(byte[] file)
{
//Attempts to backup using mechanism A
}
}
public class BackUpMechanismB : IFileBackup
{
//Implementation
public async Task Backup(byte[] file)
{
//Attempts to backup using mechanism B
}
}
Then the calling class looks like this:
public class Caller
{
private readonly IFileBackup _backupA;
private readonly IFileBackup _backupB;
public Caller(IFileBackup backupA, IFileBackup backupB)
{
_backupA = backupA;
_backupB = backupB;
}
public async Task BackupFile(byte[] file)
{
try
{
await _backupA.Backup(file);
}
catch(SomeException)
{
await _backupB.Backup(file);
}
}
}
So what I'm trying to do here is to use polymorphism. So both BackupMechanismA and BackupMechanismB implements the Backup method in their own way. In the caller I want to attempt the first mechanism and if that doesn't work we catch an exception and try the second approach.
I'm having trouble resolving the correct implementations using Autofac. I have tried with:
builder.RegisterType<BackupMechanismA>().As<IFileBackup>().AsSelf();
builder.RegisterType<BackupMechanismB>().As<IFileBackUp>().AsSelf();
But this won't work because I still need to tell the caller which of the types to resolve. How do I do that in the caller?
Also, I'm in doubt whether this design is really the right design to go with. Before this design I just had one class with two different methods, one for mechanism A and one for mechanism B and then the caller would just call the different methods in the try catch. So I wanted to refactor this because the class got quite big and I wanted to separate the two different mechanisms into their own classes.
So, can I resolve this using Autofac? And is it the right design to go with for this scenario?
Agree with Jogge that iterating IFileBackups would be a better option, but creating an interface for each type is a no go. Instead, you could add a class which provides IEnumerable<IFileBackup> (an aggregate). For example:
public class BackupBundle : IEnumerable<IFileBackup>
{
private readonly List<IFileBackup> _backups = new List<IFileBackup>();
// default constructor creates default implementations
public BackupBundle()
: this(new List<IFileBackup> {new BackUpMechanismA(), new BackUpMechanismB()}) {}
// allow users to add custom backups
public BackupBundle(IEnumerable<IFileBackup> backups)
{
foreach (var backup in backups)
Add(backup);
}
public void Add(IFileBackup backup)
{
if (backup == null) throw new ArgumentNullException(nameof(backup));
_backups.Add(backup);
}
public IEnumerator<IFileBackup> GetEnumerator()
{
foreach (var backup in _backups)
yield return backup;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class Caller
{
private readonly IEnumerable<IFileBackup> _backups;
public Caller(IEnumerable<IFileBackup> backups)
{
_backups = backups ?? throw new ArgumentNullException(nameof(backups));
}
public async Task BackupFile(byte[] file)
{
foreach (var b in _backups)
{
try
{
await b.Backup(file);
break;
}
catch (Exception e) { }
}
}
}
Registration can be done as follows:
builder.RegisterInstance(new BackupBundle()).As<IEnumerable<IFileBackup>>();
builder.RegisterType<Caller>();
which allows you to resolve by class name:
var caller = scope.Resolve<Caller>();
As you see, the BackupBundle has a dependency of BackUpMechanismA and BackUpMechanismB. You could get rid of it by introducing another layer of abstraction but I'd prefer not to do that. My main concern would be to make Caller more robust. You might want to introduce retry logic, timeouts, etc.
Try registering with a name and then resolve using the name:
builder.RegisterType<BackupMechanismA>().Named<IFileBackup>("BackUpMechanismA");
builder.RegisterType<BackupMechanismB>().Named<IFileBackUp>("BackUpMechanismB");
_backupA = container.ResolveNamed<IFileBackUp>
("BackUpMechanismA");
_backupB = container.ResolveNamed<IFileBackUp>
("BackUpMechanismB");
Resolve the instances during runtime, rather than injecting through the constructor. This will let you resolve to the respective type, as needed.
Let me know if this works.
To make your design work, you can try the next approach:
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<BackUpMechanismA>().Keyed<IFileBackup>("A");
builder.RegisterType<BackUpMechanismB>().Keyed<IFileBackup>("B");
builder.RegisterType<Caller>()
.WithParameter((p, ctx) => p.Position == 0, (p, ctx) => ctx.ResolveKeyed<IFileBackup>("A"))
.WithParameter((p, ctx) => p.Position == 1, (p, ctx) => ctx.ResolveKeyed<IFileBackup>("B"));
IContainer container = builder.Build();
var caller = container.Resolve<Caller>();
Console.ReadKey();
}
However in my opinion you probably don't need such a polymorphism here. It will be much more obvious and descriptive to implement something like this:
public async Task BackupFile(byte[] file)
{
try
{
await BackUpToAmazonS3(file);
}
catch (AmazonS3LoadingException)
{
await BackUpToLocalDisk(file);
}
}
In this example it is obvious what is going on. And there in BackUpToAmazonS3 you can use some injected AmazonS3FileBackUp and in BackUpToLocalDisk use LocalDiskFileBackUp or whatever. The point is that you don't need a polymorphism, when you don't plan to change the implementation. In your context it should be clear? that you try to put backup to some remote storage, and then, if it fails, put in on local disk. You don't need to hide the meaning here. This is your logic and should be clear, when you read the code, I suppose. Hope it helps.
In my experience, you're better off by creating an interface for each type:
public interface IFileBackup
{
Task Backup(byte[] file);
}
public interface IBackUpMechanismA : IFileBackup
{
}
public class BackUpMechanismA : IBackUpMechanismA
{
//...
}
public interface IBackUpMechanismB : IFileBackup
{
}
public class BackUpMechanismB : IBackUpMechanismB
{
//...
}
If you don't want that, what you could do is getting injected a list of IFileBackup and just iterate them. If you register BackUpMechanismA first it will be the first in the list. I'm not sure if this is guaranteed, you have to look it up.
public class Caller
{
private readonly ICollection<IFileBackup> _fileBackups;
public Caller(ICollection<IFileBackup> fileBackups)
{
_fileBackups = fileBackups;
}
public async Task BackupFile(byte[] file)
{
foreach (var fileBackup in _fileBackups)
{
try
{
await fileBackup.Backup(file);
break;
}
catch { }
}
}
}
I am using the excellent Simple Injector Ioc framework and would like to "plug in" multiple email output services ie Mandrill, MailChimp etc
My question really is am I doing this correctly as it results in a Cast at my send method.
So I have a simple IEmailOutputService
public interface IEmailOutputService
{
string Identifier { get; }
bool Send(object message, object contents);
}
And a MandrillOutputService (shortened)
public class MandrillOutputService : IEmailOutputService
{
public MandrillOutputService()
{
//DI stuff here
}
public string Identifier => "Mandrill";
public bool Send(EmailMessage message, IEnumerable<TemplateContent> templateContents)
{
if (message == null)
return false;
//send code here
return true;
}
bool IEmailOutputService.Send(object message, object contents)
{
//TODO this doesnt look right!!
var m = message as EmailMessage;
var c = contents as IEnumerable<TemplateContent>;
//forwards method onto bespoke Mandrill Send method above
return Send(m, c);
}
}
I have an EmailContext that gets the Email Output Provider for the logged in User eg "Mandrill" heres the IEmailContext
public interface IEmailContext
{
string GetProvider();
}
EmailOutputComposite is used to select correct Email Output Service
public class EmailOutputComposite : IEmailOutputService
{
private readonly IEmailContext _emailContext;
private readonly IEnumerable<IEmailOutputService> _emailOutputServices;
public string Identifier => "EmailOutputComposite";
public EmailOutputComposite(
IEmailContext emailContext, IEnumerable<IEmailOutputService> emailOutputServices)
{
this._emailContext = emailContext;
this._emailOutputServices = emailOutputServices;
}
bool IEmailOutputService.Send(object message, object contents) =>
this._emailOutputServices
.FirstOrDefault(x => x.Identifier.ToLower() == this._emailContext.GetProvider())
.Send(message, contents);
}
and finally registrations in Simple Injector
container.RegisterCollection(typeof(IEmailOutputService), new[]
{
typeof(MandrillOutputService)
//other emailOutputServices to go here
});
container.Register(typeof(IEmailOutputService), typeof(EmailOutputComposite),
Lifestyle.Singleton);
So my question is am I doing this correctly or is there a better way. I have to get the Users Email Provider (Mandrill) from Database so cant think of another way to do this but was concerned with the Cast I have to do in MandrillOutputService.Send method.
Wouldn't it be simpler to use the Strategy and Factory patterns, forgive me I'm going to change the implementation a bit:
For container registrations:
container.Register<EmailProviderFactory>(Lifestyle.Scoped);
container.Register<MandrillOutputService>(Lifestyle.Scoped);
container.Register<OtherOutputService>(Lifestyle.Scoped);
Then use a factory to resolve my email providers:
public class EmailProviderFactory
{
private readonly Container container;
public EmailProviderFactory(Container container)
{
this.container = container;
}
public IEmailOutputService Create(string provider)
{
switch (provider)
{
case "Mandrill": // should be in a constants class
return container.GetInstance<MandrillOutputService>();
case "Other": // should be in a constants class
return container.GetInstance<OtherOutputService>();
default: throw new ArgumentOutOfRangeException("provider");
}
}
}
I've changed the IEmailOutputService to have one method with explicit types:
public interface IEmailOutputService
{
bool Send(EmailMessage message, IEnumerable<TemplateContent> contents);
}
The email providers :
public class MandrillOutputService : IEmailOutputService
{
public bool Send(EmailMessage message, IEnumerable<TemplateContent> templateContents)
{
// ...
}
}
public class OtherOutputService : IEmailOutputService
{
public bool Send(EmailMessage message, IEnumerable<TemplateContent> templateContents)
{
// ...
}
}
Usage:
foreach(var userEmailProvider in UserEmailProviders) {
// I'm assuming the factory is injected
var emailService = _emailProviderFactory.Create(userEmailProvider.Name);
emailService.Send(new EmailMessage(), new List<TemplateContent>());
}
I do not think you need IEmailContext or a EmailOutputComposite. By using the EmailProviderFactory you will only create a specific provider when you need it.
I see two problems in your design:
You are violating the Liskov Substitution Principle in your MandrillOutputService by accepting only a subset of the accepted types of the IEmailOutputService abstraction; this might cause the appliation to break at runtime when the user supplies values that are invalid for that specific implementation.
The Identifier property on the IEmailOutputService violates the Interface Segration Principle, because it is a method that consumers don't use. The only class that is actually interested in this property is the EmailOutputComposite. Removing the Identifier from the abstraction has the advantage that it can simplify unit testing, since there is less code that a consumer can call. It also simplifies the interface, which is always a good thing.
I'm unsure how to fix the LSP principle, because its unclear to me how other implementations look like.
With respect to the ISP violation, you can do the following to fix it:
Mark the implementations instead with an attribute that defines their Identifier. This allows you to remove the property from the interface, but the downside is that the Composite can only filter those services in case the actual types are injected (and not decorated, because that disallows you from retrieving those attributes).
You let the Composite depend on the actual concrete implementations and implement a switch-case statement inside the Composite. This again allows you to remove the property from the interface, but downside is that you will have to update the composite every time a new implementation is added (which might not be that bad if you consider the Composite part of your Composition Root).
You define a dictionary of IEmailOutputServices during the registration process, where the Identifier is the dictionary's key. This removes the need to have the Identifier as part of the abstraction, but also removes the identifier from the implementation (which might actually be something good).
Here's an example of this last example:
container.RegisterSingleton<IEmailOutputService, EmailOutputComposite>();
container.RegisterSingleton(new Dictionary<string, Func<IEmailOutputService>>()
{
"Mandrill", CreateEmailServiceProducer<MandrillOutputService>(container),
"other", CreateEmailServiceProducer<Other>(container),
// ..
});
privte static Func<IEmailOutputService> CreateEmailServiceProducer<T>(Container c)
where T : IEmailOutputService =>
Lifestyle.Transient.CreateProducer<IEmailOutputService, T>(c).GetInstance;
Where the Composite is implemented as follows:
public class EmailOutputComposite : IEmailOutputService
{
private readonly IEmailContext _emailContext;
private readonly Dictionary<string, Func<IEmailOutputService>> _emailOutputServices;
public EmailOutputComposite(
IEmailContext emailContext,
Dictionary<string, Func<IEmailOutputService>> emailOutputServices)
{
_emailContext = emailContext;
_emailOutputServices = emailOutputServices;
}
public bool Send(object m, object c) => Service.Send(m, c);
IEmailOutputService Service => _emailOutputServices[_emailContext.GetProvider()]();
}
Whether or not this is actually an improvement is up to you.
I am facing a unique problem. We have a download functionality in our application in which we have a drop-down which contains type of file user need to download i.e. pdf,csv or excel
To implement this problem we have create one Interface IFileDownaload and three different class clsCSV,ClsPDF and clsExcel which are implemented by IFileDownaload
Now my problem is how to inititate a class on the basis of Dropdown value because i dont want to write down if-else statement
if(option=="pdf") type
because in future if we introduce a new file download type then it will impact us to re-write whole logic again
Any suggestion
You can define abbreviation for each class you have, so that you'll have something like this:
public interface IFileDownload
{
string Abbreviation { get; }
}
public class PDFDonwload : IFileDownload
{
public string Abbreviation { get; private set; }
}
Then you can make some class, i.e. factory, which have instances of all filedownloaders you have and which iterates through their Abbreviations till it finds proper class. It can be implemented like this:
public static class DownloadHander
{
private static List<IFileDownload> _handlers;
static DownloadHander()
{
_handlers = new List<IFileDownload>();
}
public static void Initialize()
{
_handlers.Add(new PDFDonwload());
}
public static Stream HandleDownload(string abbreviation)
{
foreach (var fileDownload in _handlers)
{
if (fileDownload.Abbreviation == abbreviation)
{
//and here you make a stream for client
}
}
throw new Exception("No Handler");
}
}
When I have a number of classes which implement a certain type and those classes are stateless services rather than entities, I use a Registry rather than a Factory.
Your Registry has instances of all the IFileDownload-implementing classes injected into it in an array:
public class FileDownloaderRegistry
{
private readonly IFileDownload[] _downloaders;
public FileDownloaderRegistry(IFileDownload[] downloaders)
{
_downloaders = downloaders;
}
}
You then have a property on IFileDownload which indicates the file type handled by the downloader:
public interface IFileDownload
{
string FileType { get; }
// etc.
}
And finally a method on your Registry which takes the file type and delegates the work to the appropriate downloader:
public string DownloadFile(string fileName, string fileType)
{
var handlingDownloader = _downloaders
.FirstOrDefault(d => d.FileType == fileType);
if (handlingDownloader == null)
{
// Probably throw an Exception
}
return handlingDownloader.Download(fileName);
}
DI containers will often implicitly understand arrays, so just registering the various IFileDownloads should end up with them in the array injected into the Registry's constructor. e.g. with StructureMap you use:
For<IFileDownload>().Use<ClsCSV>();
For<IFileDownload>().Use<ClsPDF>();
For<IFileDownload>().Use<ClsExcel>();
Adding a new IFileDownload is then a matter of writing the class and adding it to the set of IFileDownloads registered with your DI container. You can also have the container manage the lifetimes of each object so (if they're stateless) they're only instantiated once each, when they're first needed.
C#. I have a base class called FileProcessor:
class FileProcessor {
public Path {get {return m_sPath;}}
public FileProcessor(string path)
{
m_sPath = path;
}
public virtual Process() {}
protected string m_sath;
}
Now I'd like to create to other classes ExcelProcessor & PDFProcessor:
class Excelprocessor: FileProcessor
{
public void ProcessFile()
{
//do different stuff from PDFProcessor
}
}
Same for PDFProcessor, a file is Excel if Path ends with ".xlsx" and pdf if it ends with ".pdf". I could have a ProcessingManager class:
class ProcessingManager
{
public void AddProcessJob(string path)
{
m_list.Add(Path;)
}
public ProcessingManager()
{
m_list = new BlockingQueue();
m_thread = new Thread(ThreadFunc);
m_thread.Start(this);
}
public static void ThreadFunc(var param) //this is a thread func
{
ProcessingManager _this = (ProcessingManager )var;
while(some_condition) {
string fPath= _this.m_list.Dequeue();
if(fPath.EndsWith(".pdf")) {
new PDFProcessor().Process();
}
if(fPath.EndsWith(".xlsx")) {
new ExcelProcessor().Process();
}
}
}
protected BlockingQueue m_list;
protected Thread m_thread;
}
I am trying to make this as modular as possible, let's suppose for example that I would like to add a ".doc" processing, I'd have to do a check inside the manager and implement another DOCProcessor.
How could I do this without the modification of ProcessingManager? and I really don't know if my manager is ok enough, please tell me all your suggestions on this.
I'm not really aware of your problem but I'll try to give it a shot.
You could be using the Factory pattern.
class FileProcessorFactory {
public FileProcessor getFileProcessor(string extension){
switch (extension){
case ".pdf":
return new PdfFileProcessor();
case ".xls":
return new ExcelFileProcessor();
}
}
}
class IFileProcessor{
public Object processFile(Stream inputFile);
}
class PdfFileProcessor : IFileProcessor {
public Object processFile(Stream inputFile){
// do things with your inputFile
}
}
class ExcelFileProcessor : IFileProcessor {
public Object processFile(Stream inputFile){
// do things with your inputFile
}
}
This should make sure you are using the FileProcessorFactory to get the correct processor, and the IFileProcessor will make sure you're not implementing different things for each processor.
and implement another DOCProcessor
Just add a new case to the FileProcessorFactory, and a new class which implements the interface IFileProcessor called DocFileProcessor.
You could decorate your processors with custom attributes like this:
[FileProcessorExtension(".doc")]
public class DocProcessor()
{
}
Then your processing manager could find the processor whose FileProcessorExtension property matches your extension, and instantiate it reflexively.
I agree with Highmastdon, his factory is a good solution. The core idea is not to have any FileProcessor implementation reference in your ProcessingManager anymore, only a reference to IFileProcessor interface, thus ProcessingManager does not know which type of file it deals with, it just knows it is an IFileProcessor which implements processFile(Stream inputFile).
In the long run, you'll just have to write new FileProcessor implementations, and voila. ProcessingManager does not change over time.
Use one more method called CanHandle for example:
abstract class FileProcessor
{
public FileProcessor()
{
}
public abstract Process(string path);
public abstract bool CanHandle(string path);
}
With excel file, you can implement CanHandle as below:
class Excelprocessor: FileProcessor
{
public override void Process(string path)
{
}
public override bool CanHandle(string path)
{
return path.EndsWith(".xlsx");
}
}
In ProcessingManager, you need a list of processor which you can add in runtime by method RegisterProcessor:
class ProcessingManager
{
private List<FileProcessor> _processors;
public void RegisterProcessor(FileProcessor processor)
{
_processors.Add(processor)
}
....
So LINQ can be used in here to find appropriate processor:
while(some_condition)
{
string fPath= _this.m_list.Dequeue();
var proccessor = _processors.SingleOrDefault(p => p.CanHandle(fPath));
if (proccessor != null)
proccessor.Process(proccessor);
}
If you want to add more processor, just define and add it into ProcessingManager by using
RegisterProcessor method. You also don't change any code from other classes even FileProcessorFactory like #Highmastdon's answer.
You could use the Factory pattern (a good choice)
In Factory pattern there is the possibility not to change the existing code (Follow SOLID Principle).
In future if a new Doc file support is to be added, you could use the concept of Dictionaries. (instead of modifying the switch statement)
//Some Abstract Code to get you started (Its 2 am... not a good time to give a working code)
1. Define a new dictionary with {FileType, IFileProcessor)
2. Add to the dictionary the available classes.
3. Tomorrow if you come across a new requirement simply do this.
Dictionary.Add(FileType.Docx, new DocFileProcessor());
4. Tryparse an enum for a userinput value.
5. Get the enum instance and then get that object that does your work!
Otherwise an option: It is better to go with MEF (Managed Extensibility Framework!)
That way, you dynamically discover the classes.
For example if the support for .doc needs to be implemented you could use something like below:
Export[typeof(IFileProcessor)]
class DocFileProcessor : IFileProcessor
{
DocFileProcessor(FileType type);
/// Implement the functionality if Document type is .docx in processFile() here
}
Advantages of this method:
Your DocFileProcessor class is identified automatically since it implements IFileProcessor
Application is always Extensible. (You do an importOnce of all parts, get the matching parts and Execute.. Its that simple!)
I have a situation where I have 8 steps (think of it as a wizard). Each step consists of something different so I've created 8 classes. Each of the classes need some information from the previous steps (classes). All the classes are called from one main class. The neatiest way I've found to handle this situation is :
public void Main()
{
var step1 = new Step1();
step1.Process();
var step2 = new Step2(step1);
step2.Process();
var step3 = new Step3(step1, step2);
//...
var step8 = new Step8(step1, step2, step3, step4, step5, step6, step7);
step8.Process();
}
Obviously, this is a mess. I don't want to send that many parameters and I don't want to use static classes (probably not a good practice).
How would you handle such situation?
This sounds to me like something that you could accomplish via a Chain of Responsibility Pattern. That is the direction that I would look into at least.
If you go down that path, then you will leave yourself open to a cleaner implementation of adding/removing steps in the future.
And, as far as the multiple data sets, John Koerner is correct in that you should have one data model that is updated in each step. This will allow you to implement a clean chain of responsibility.
Have a single class that is your datamodel that can be used throughout the processes. The steps update their piece of the datamodel and that is the only object passed to each subsequent step.
Seems like Java's inner classes are better suited for this than anything C# has. But, C# is so much better in so many other aspects, we'll let this one pass.
You should create one class that contains all your data. If your steps are simple, you should have one method per step in that one class. If your steps are complicated, separate them into classes, but give each of them access to the data class.
You can have interface IProcess with method Run(Wizard) and property Name, several processes and everyone inherits IProcess, and class Wizard that contain processes to run in the list. So:
class Wizard
{
private IList<IProcess> processes = new List<IProcess();
public T GetProcess<T>(string name)
where T : IProcess
{
return (T)processes.Single(x => x.Name == name);
}
public void Run()
{
foreach (var proc in processes)
proc.Run(this);
}
}
Every process can have access to the wizard using argument of the Run method, or just have it in the constructor. By calling wizard.GetProcess<Process1>("some name") you can have your process that was previously executed (you can add a check).
Other option is to contain results in the Wizard class.
This is only one of many variants. You can look at Chain of Responsibility Pattern, like Justin suggests
I would say a classical example for a variation of a Chain-Of-Responsibility.
Here is an example:
class Request
{
private List<string> _data;
public IEnumerable<string> GetData()
{
return _data.AsReadOnly();
}
public string AddData(string value)
{
_data.Add(value);
}
}
abstract class Step
{
protected Step _nextStep;
public void SetSuccessor(Step step)
{
_nextStep = step;
}
public abstract void Process(Request request);
}
sealed class Step1 : Step
{
public override void Process(Request request)
{
var data = request.GetData();
Console.Write("Request processed by");
foreach (var datum in data)
{
Console.Write(" {0} ", datum);
}
Console.WriteLine("Now is my turn!");
request.AddData("step1");
_nextStep.Process(request);
}
}
// Other steps omitted.
sealed class Step8 : Step
{
public override void Process(Request request)
{
var data = request.GetData();
Console.Write("Request processed by");
foreach (var datum in data)
{
Console.Write(" {0} ", datum);
}
Console.WriteLine("Guess we're through, huh?");
}
}
void Main()
{
var step1 = new Step1();
// ...
var step8 = new Step8();
step8.SetSuccessor(step1);
var req = new Request();
step1.Process(req);
}
Create just one class and use different methods as steps
class Wizard
{
int someIntInfo;
string some StringInfo;
...
public void ProcessStep1();
public void ProcessStep2();
public void ProcessStep3();
public void ProcessStep4();
}
Or create a step and an info interface and declare the wizard like this by passing the same info to all steps
interface IWizardInfo
{
int someIntInfo { get set; }
string someStringInfo { get set; }
...
}
interface IStep
{
void Process(IWizardInfo info);
}
class Wizard
{
IWizardInfo _info = ....;
IStep[] _steps = new IStep[] { new Step1(), new Step2(), ... };
int _currentStep;
void ProcessCurrentStep()
{
_steps[_currentStep++].Process(_info);
}
}
EDIT:
Create a compound class which can hold all previous steps
class Step1 { public Step1(AllSteps steps) { steps.Step1 = this; } ... }
class Step2 { public Step2(AllSteps steps) { steps.Step2 = this; } ... }
class Step3 { public Step3(AllSteps steps) { steps.Step3 = this; } ... }
class AllSteps
{
public Step1 Step1 { get; set; }
public Step2 Step2 { get; set; }
public Step3 Step3 { get; set; }
}
Pass the same info to all steps. The steps are responsible to add themselves to the info
AllSteps allSteps = new AllSteps();
var stepX = new StepX(allSteps);
Why not create one single class for all of your steps and implement state management within that class? e.g.
private class Steps
{
private int _stepIndex = 0;
public void Process()
{
switch(_stepIndex)
{
case 0: // First Step
... // Perform business logic for step 1.
break;
case 1: // Second Step
... // Perform business logic for step 2.
break;
}
_stepIndex++;
}
}
I would have two ArrayLists (or depending on your class and method structure they might be simple Lists) - one for methods (as delegates) and one for results.
So, foreach method would go through delegates and invoke them with results list as parameter (you might accommodate your methods to accept such parametars and work with them) and add result to results list.