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!)
Related
For my project purpose I need to send metrics to AWS.
I have main class called SendingMetrics.
private CPUMetric _cpuMetric;
private RAMMetric _ramMetric;
private HDDMetric _hddMetric;
private CloudWatchClient _cloudWatchClient(); //AWS Client which contains method Send() that sends metrics to AWS
public SendingMetrics()
{
_cpuMetric = new CPUMetric();
_ramMetric = new RAMMetric();
_hddMetric = new HDDMetric();
_cloudwatchClient = new CloudwatchClient();
InitializeTimer();
}
private void InitializeTimer()
{
//here I initialize Timer object which will call method SendMetrics() each 60 seconds.
}
private void SendMetrics()
{
SendCPUMetric();
SendRAMMetric();
SendHDDMetric();
}
private void SendCPUMetric()
{
_cloudwatchClient.Send("CPU_Metric", _cpuMetric.GetValue());
}
private void SendRAMMetric()
{
_cloudwatchClient.Send("RAM_Metric", _ramMetric.GetValue());
}
private void SendHDDMetric()
{
_cloudwatchClient.Send("HDD_Metric", _hddMetric.GetValue());
}
Also I have CPUMetric, RAMMetric and HDDMetric classes that looks pretty much similar so I will just show code of one class.
internal sealed class CPUMetric
{
private int _cpuThreshold;
public CPUMetric()
{
_cpuThreshold = 95;
}
public int GetValue()
{
var currentCpuLoad = ... //logic for getting machine CPU load
if(currentCpuLoad > _cpuThreshold)
{
return 1;
}
else
{
return 0;
}
}
}
So the problem I have is that clean coding is not satisfied in my example. I have 3 metrics to send and if I need to introduce new metric I will need to create new class, initialize it in SendingMetrics class and modify that class and that is not what I want. I want to satisfy Open Closed principle, so it is open for extensions but closed for modifications.
What is the right way to do it? I would move those send methods (SendCPUMetric, SendRAMMetric, SendHDDMetric) to corresponding classes (SendCPUMetric method to CPUMetric class, SendRAMMEtric to RAMMetric, etc) but how to modfy SendingMetrics class so it is closed for modifications and if I need to add new metric to not change that class.
In object oriented languages like C# the Open Closed Principle (OCP) is usually achieved by using the concept of polymorphism. That is that objects of the same kind react different to one and the same message. Looking at your class "SendingMetrics" it's obvious that the class works with different types of "Metrics". The good thing is that your class "SendingMetrics" talks to a all types of metrics in the same way by sending the message "getData". Hence you can introduce a new abstraction by creating an Interface "IMetric" that is implemented by the concrete types of metrics. That way you decouple your "SendingMetrics" class from the concrete metric types wich means the class does not know about the specific metric types. It only knows IMetric and treats them all in the same way wich makes it possible to add any new collaborator (type of metric) that implements the IMetric interface (open for extension) without the need to change the "SendingMetrics" class (closed for modification). This also requires that the objects of the different types of metrics are not created within the "SendingMetrics" class but e.g. by a factory or outside of the class and being injected as IMetrics.
In addition to using inheritance to enable polymorphism and achiving OCP by introducing the interface IMetric you can also use inheritance to remove redundancy. Which means you can introduce an abstract base class for all metric types that implements common behaviour that is used by all types of metrics.
Your design is almost correct. You got 3 data retriever and 1 data sender. So it's easy to add more metric (more retriever) (open for extensions) without affecting current metrics (closed for modifications), you just need a bit more refactor to reduce duplicated code.
Instead of have 3 metrics classes look very similar. Only below line is different
var currentCpuLoad = ... //logic for getting machine CPU load
You can create a generic metric like this
internal interface IGetMetric
{
int GetData();
}
internal sealed class Metric
{
private int _threshold;
private IGetMetric _getDataService;
public Metric(IGetMetric getDataService)
{
_cpuThreshold = 95;
_getDataService = getDataService;
}
public int GetValue()
{
var currentCpuLoad = _getDataService.GetData();
if(currentCpuLoad > _cpuThreshold)
{
return 1;
}
else
{
return 0;
}
}
}
Then just create 3 GetMetric classes to implement that interface. This is just 1 way to reduce the code duplication. You can also use inheritance (but I don't like inheritance). Or you can use a Func param.
UPDATED: added class to get CPU metric
internal class CPUMetricService : IGetMetric
{
public int GetData() { return ....; }
}
internal class RAMMetricService : IGetMetric
{
public int GetData() { return ....; }
}
public class AllMetrics
{
private List<Metric> _metrics = new List<Metric>()
{
new Metric(new CPUMetricService());
new Metric(new RAMMetricService());
}
public void SendMetrics()
{
_metrics.ForEach(m => ....);
}
}
So I have a few instances where I'd like to be able to do this but essentially I'd like to be able to wrap all calls to a Superclass in a derived type. Right now I'm trying to wrap all calls to base method in an Impersonator but I can see other uses for this as well.
An example being
public void CopyFile(string filePath, string destPath)
{
using(var I = new Impersonator("user", ".", "password"))
{
base.CopyFile(string filePath, string destPath);
}
}
Another convenient use might be
public void CopyFile(string filePath, string destPath)
{
try
{
base.CopyFile(string filePath, string destPath);
} catch(Exception e)
{
Log(e.Message);
}
}
Now I'd like to wrap all base calls similarly. Is there a convenient way to do this or do I have to wrap all of these manually?
I'm looking for something like a "foreach baseMethod in Superclass Do This"
Perhaps finding some way to capture incoming calls to the class and wrapping them as an action?
public void ActionWrapper(Action action)
{
try
{
action.Invoke();
} catch(Exception e)
{
Log(e.Message);
}
}
But how would I catch calls to the class in that way?
Honestly this is just to make the class more maintainable and reduce code bloat. I'm open to these or any other approaches.
First, I want to applaud your instinct to deconstruct code this way. Separating concerns like error handling/logging and security/identity from your business logic can do wonders for maintainability.
What you're describing is known as either decoration or interception. Mark Seemann has a good blog post comparing the two approaches in the context of logging.
Without using external tools (like a DI or AOP framework), I think the ActionWrapper method you proposed is a good start. I modified it to show impersonation rather than logging, since I think impersonation is a more interesting use case:
public void ActionWrapper(Action action)
{
using(var I = new Impersonator("user", ".", "password"))
{
action.Invoke();
}
}
So the question is: How to apply this method efficiently?
Let's assume your existing class is:
public class FileCopier
{
public void CopyFile(string filePath, string destPath)
{
// Do stuff
}
}
You could, as you suggested, create a derived class to add impersonation:
public class FileCopierWithImpersonation : FileCopier
{
public void CopyFile(string filePath, string destPath)
=> WithImpersonation(base.CopyFile(filePath, destPath));
public void WithImpersonation(Action action)
{
using(var I = new Impersonator("user", ".", "password"))
{
action.Invoke();
}
}
}
Here, FileCopierWithImpersonation serves as a decorator over FileCopier, implemented via inheritance. The WithImpersonation method serves as an interceptor that can apply an impersonation scope over any method.
That should work well enough, but it forces some compromises in implementation. The base class's methods will all need to be marked as virtual. The child class's constructor might need to pass arguments to the base class. It will be impossible to unit test the child class's logic independently of the base class's logic.
So, you might want to extract an interface (IFileCopier) and apply the decorator using composition rather than inheritance:
public class FileCopierWithImpersonation : IFileCopier
{
private readonly IFileCopier _decoratee;
public FileCopierWithImpersonation(IFileCopier decoratee)
{
// If you don't want to inject the dependency, you could also instantiate
// it here: _decoratee = new FileCopier();
_decoratee = decoratee;
}
public void CopyFile(string filePath, string destPath)
=> WithImpersonation(_decoratee.CopyFile(filePath, destPath));
public void WithImpersonation(Action action)
{
using(var I = new Impersonator("user", ".", "password"))
{
action.Invoke();
}
}
}
If you're using Visual Studio 2019, there's a refactoring option to "Implement Interface through..." that will automatically implement an interface by calling methods of a dependency of the same type. After that, a simple find/replace should be all that's needed to add the interceptor.
You could also look into code generation tools, like T4 Templates to auto-generate the decorators. Beware, though, that T4 is not supported in .NET Core. It looks to be a legacy technology at this point.
From a good design perspective, I would advise not to do this for 2 reasons:
If catching exception is the sole purpose, then don't do it. Catching and swallowing system exceptions is a bad practice
If you want to do some pre-setup or post-processing on every method of base then may be you should choose composition rather than inheritance here.
However, if you have made up your mind then using an array of delegates can solve your problem.
class Derived : Base
{
private Action[] AllActions;
public Derived()
{
AllActions = new Action[]
{
base.DoSomething1,
base.DoSomething2,
base.DoSomethingMore
};
}
public ActionWrapper(int index)
{
try
{
AllActions[index].Invoke();
} catch(Exception e)
{
Log(e.Message);
}
}
}
For simplicity I have used an array. Use a dictionary to keep a key for each base class method.
I see AOP has been suggested but not expanded upon, so I will attempt to cover it then.
I am assuming you are open to making your base class methods virtual. In this case using a Castle DynamicProxy might give you the flexibility you are after. It will allow you to not only inject code before and after parent method execution, but also change input/output parameters depending on your business requirements.
Here's an artist's impression on what your class might look like should you opt for it:
public class FileCopier
{
public virtual void CopyFile(string filePath, string destPath)
{
// do things here
}
}
public class ImpersonationInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
using (var I = new Impersonator("user", ".", "password"))
{
invocation.Proceed();
}
}
}
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
}
catch (Exception e)
{
Log(e.Message);
}
}
}
public class CustomProxyGenerationHook : IProxyGenerationHook
{
public void MethodsInspected() {}
public void NonProxyableMemberNotification(Type type, MemberInfo memberInfo) {}
public bool ShouldInterceptMethod(Type type, MethodInfo methodInfo)
{
// decide whether you need to intercept your method here
return true;
}
}
void Main()
{
var generator = new ProxyGenerator();
var options = new ProxyGenerationOptions(new CustomProxyGenerationHook());
var fileCopierProxy = generator.CreateClassProxy(typeof(FileCopier),
options
new IInterceptor[] { // specify list of interceptors
new ImpersonationInterceptor(),
new LoggingInterceptor()
}
) as FileCopier;
fileCopierProxy.CopyFile("src", "dest");
}
Even if you've got a ton of classes and modifying them all by hand is not feasible, you can still work around it by opting for yet another technique called assembly weaving. Project Fody is a good starting point, and this particular problem is best solved with Virtuosity plugin - it basically rewrites your assembly on build to mark all methods virtual so you don't have to do it yourself.
public static T DecoratorActions<T>(string desc, Func<T> func)
{
return Log(desc, () => ImpersonateAndAct(func));
}
public static void DecoratorActions(string desc, Action action)
{
Log(desc, () => ImpersonateAndAct(action));
}
public string Read(string filepath)
{
return DecoratorActions($"Reading file at '{filepath}'",
() => fileService.Read(filepath));
}
Based on these very helpful answers I've been able to determine that, while I may not be able to automatically wrap all methods of a class. I can at least reduce boilplate code and separate concerns by using the Decorator Pattern instead of the standard inheritance.
As such I have a Log method which calls "Entering {methodName}" and "Exiting {methodName}" as well as try/catching for exceptions which it also logs before throwing.
Additionally an inline way of impersonating for a specific action in the ImpersonateAndAct method.
Both of these return type of T so they wrap calls to my decorated fileService without interfering with the products of those methods.
I marked #Xander as the correct answer as he was the chief inspiration for this approach but I wanted to leave an answer to share what I came up with.
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.
We're working with XML and want a common interface amongst the main XML class and all of its components. However, sub-components of the XML class need additional methods, but they also need the main component's methods. Seems like a great use for inheritance.
Here is some code I wrote to accomplish this task. Hopefully, you can get a good idea of what we're going for based on usage:
using System;
namespace SampleNamespace
{
public class SampleClass
{
public static void Main()
{
var xmlDocumentFiles = new XmlDocumentFiles();
xmlDocumentFiles.Files.RootFile.SetFileName("Example.xml");
System.Console.WriteLine(
xmlDocumentFiles.Files.RootFile.GetFileName()
);
}
}
public class XmlDocumentFilesRoot
{
protected string _rootFileName;
public FilesClass Files { get { return (FilesClass) this; } }
}
public class FilesClass : XmlDocumentFilesRoot
{
public RootFileClass RootFile { get { return (RootFileClass) this; } }
}
public class RootFileClass : FilesClass
{
public void SetFileName( string newTitle )
{
_rootFileName = newTitle;
}
public string GetFileName()
{
return _rootFileName;
}
}
public class XmlDocumentFiles : RootFileClass
{
}
}
I was able to cast to child classes and to my surprise it runs just fine. Assuming nothing is put inside of the sub-classes other than methods which wouldn't make sense in the parent, will there ever be any problems (weird compilation errors, runtime crashes) with this class structure?
Are there any alternatives? I had initially tried nested classes + extension methods located outside of the main class, but there was a lot of code needed to set that up. See: https://stackoverflow.com/questions/19415717/using-c-sharp-extension-methods-on-not-in-nested-classes-to-establish-a-common
Extending functionality of a class, sounds like a decorator pattern.
Here's a head-first pdf on this subject:
http://oreilly.com/catalog/hfdesignpat/chapter/ch03.pdf
Also; I would like to discourage the triple '.' :
xmlDocumentFiles.Files.RootFile.SetFileName("Example.xml");
2 is evil, if you need 3: you will definitely lose maintainability.
Hope it helps.
I'm currently working on a C# program that creates a List, of object Task, the object Task is a base class and many other inherit from it. What I want to is compare the type of one of the object within said list to see which form should be opened in order to edit it.
This is the code I have already created.
private void itemEdit_Click(object sender, EventArgs e)
{
int edi = taskNameBox.SelectedIndex;
Task checkTask = todoList.ElementAt(edi);
if(checkTask.GetType is Note)
{
noteBuilder editNote = new noteBuilder(todoList);
editNote.Show();
}
else if(checkTask.GetType is extendedTask)
{
extendedTaskBuilder editTask = new extendedTaskBuilder(todoList);
editTask.Show();
}
else if(checkTask.GetType is Reminder)
{
reminderBuilder editReminder = new reminderBuilder(todoList);
editReminder.Show();
}
else if (checkTask.GetType is Appointment)
{
appointmentBuilder editAppointment = new appointmentBuilder(todoList);
editAppointment.Show();
}
}
On a secondary note would it be easier if instead of passing the list between the forms and generating a new object of the form that display information that I instead pass a single object between forms and just update the form every time a new element is added to the list.
Many thanks
Have you tried checking like this:
if (checkTask is Note)
{
}
...
Have you considered creating a base class for all types you are now switching between and call a virtual (abstract) method?
Put all code now in the if in the overridden abstract method.
Advantages:
- The intelligence of the switch is within the classes where it belongs.
- When a new type is added you get a compiler error to also add this feature to the new type.
I suggest that instead of doing that series of ‘if’ clauses, you use inheritance to achieve what ou need. First you create a virtual method in your base class. A virtual method means it won't have any implementation in the base class, only the declaration:
public class Task
{
(...)
public virtual void ShowEditForm(IList todoList);
(...)
}
Then you create the child class methods (I'm assuming the todoList object is a IList, but just change it if it is not).
public class Note: Task
{
(...)
public override void ShowEditForm(IList todoList)
{
(new noteBuilder(taskToEdit)).Show();
}
(...)
}
public class Reminder: Task
{
(...)
public override void ShowEditForm(IList todoList)
{
(new reminderBuilder(taskToEdit)).Show();
}
(...)
}
I didn't write all the classes, but I think you've got the idea. To call the method, you just call the method from Task class, and the right method will be executed:
int edi = taskNameBox.SelectedIndex;
Task checkTask = todoList.ElementAt(edi);
checkTask.ShowEditForm(todoList);
This way, when you want to create new types of Task, you just have to create the child class, with the proper method, and the inheritance system will do the rest.
One more thing, the override keyword in the child method declaration is important, because it says to the compiler that this method should be called even if you call it from the BaseClass.
First, to your second note. What you are talking about doing is having a global object that all forms refer to in some parent. That can work, however you will need to make sure there is some mechanism in place that makes sure all of the forms are synchronized when one changes, and this can get messy and a bit of a mess to maintain. I am not necessarily advocating against it per say, but just adding words of caution when considering it :)
As to your posted code, it would probably be better to turn this into a Strategy Pattern approach, where all forms inherit from a base class/interface which has a Show method. Then all you need to do is call checkTask.Show(todoList);. If you do not want that coming from the Task, then you could have your forms all inherit from the above base and you could use a factory pattern that takes in the Task and list and returns the appropriate form on which you simply call form.Show();
Code like this is difficult to maintain, you are probably better off abstracting this out, like so (assuming Task is not the one included in .net):
public interface IBuilder
{
void Show();
}
public abstract class Task
{
// ...
public abstract IBuilder GetBuilder(TaskList todoList);
// ...
}
public class Note : Task
{
public override IBuilder GetBuilder(TaskList todoList)
{
return new noteBuilder(todoList);
}
// ...
}
// etc.
private void itemEdit_Click(object sender, EventArgs e)
{
int edi = taskNameBox.SelectedIndex;
Task checkTask = todoList.ElementAt(edi);
IBuilder builder = checkTask.GetBuilder(todoList);
builder.Show();
}
Alternately, you can use an injection pattern:
public abstract class Task
{
protected Task(Func<TaskList, IBuilder> builderStrategy)
{
_builderStrategy = builderStrategy;
}
public IBuilder GetBuilder(TaskList todoList))
{
return _builderStrategy(todolist);
}
}
public class Note : Task
{
public Note(Func<TaskList, IBuilder> builderStrategy) : base(builderStrategy) {}
}
// ...
note = new Note(x => return new noteBuilder(x));