Design pattern for enum combination (method parameters) - c#

I have a block of code similar to this one:
public bool DoMyThings(EnumRootAction root, EnumChildAction child){
switch(root){
case EnumRootAction.Type1:
switch(child){
case EnumChildAction.Ac1:
// DO something
break;
case EnumChildAction.Ac2:
// DO something
break;
default: // child is not child of type root
return false;
}
break;
case EnumRootAction.Type2:
switch(child){
case EnumChildAction.Ac1:
// DO something
break;
case EnumChildAction.Ac3:
// DO something
break;
default: // child is not child of type root
return false;
}
break;
... // etc...
default:
return false;
}
return true;
}
However, I do believe that it is a bad looking piece of code... :) ... the "consumer" of this service does not know the correct combination of root/child that are valid and might pass a wrong one.
I thought of "spiting" it into several methods, something like: DoMyThingsForRootType1(EnumChildActionForType1 child) but in a long term term this is not so easy to change in my case. I explain why: if the signature of my service changes continuously I need to update the service protocol of all my real time clients.... update source code and deploy it again.... and at the present day the client can simply make these changes manually by changing some app.settings values.
At this point I am providing a single sheet of paper with the correct combinations but this is crap as well in my eyes.
Perhaps I am just looking at this from one perspective and somehow I am not being able to expand my horizons... this is why I would like to ear some feedback from you guys/gals...
Is there a better design pattern for this?
At least some kind of way to inform the service's client of the valid combinations....
Thanks.

If you can use interfaces or base classes instead of enums you can harness the power of object-orientation to determine how the combinations are to be evaluated. This allows you to group the root/child action functionality in an easy-to-understand and easy-to-maintain way. It is somewhat long-winded however:
public interface IChildAction
{
}
public class ChildAction1 : IChildAction
{
}
public class ChildAction2 : IChildAction
{
}
public class ChildAction3 : IChildAction
{
}
public abstract class BaseRootAction
{
public virtual bool Process(ChildAction1 action)
{
return false;
}
public virtual bool Process(ChildAction2 action)
{
return false;
}
public virtual bool Process(ChildAction3 action)
{
return false;
}
}
public class RootAction1 : BaseRootAction
{
public override bool Process(ChildAction1 action)
{
Console.WriteLine("Root action 1, Child action 1");
return true;
}
public override bool Process(ChildAction2 action)
{
Console.WriteLine("Root action 1, Child action 2");
return true;
}
}
public class RootAction2 : BaseRootAction
{
public override bool Process(ChildAction1 action)
{
Console.WriteLine("Root action 2, Child action 1");
return true;
}
public override bool Process(ChildAction3 action)
{
Console.WriteLine("Root action 2, Child action 3");
return true;
}
}
public class RootAction3 : BaseRootAction
{
public override bool Process(ChildAction2 action)
{
Console.WriteLine("Root action 3, Child action 2");
return true;
}
}
public bool DoMyThings(BaseRootAction rootAction, IChildAction childAction)
{
return rootAction.Process((dynamic)childAction);
}
I also include my test method for completeness:
private void Test()
{
List<BaseRootAction> rootActions = new List<BaseRootAction>() { new RootAction1(), new RootAction2(), new RootAction3()};
List<IChildAction> childActions = new List<IChildAction>() { new ChildAction1(), new ChildAction2(), new ChildAction3()};
foreach (BaseRootAction rootAction in rootActions)
{
foreach (IChildAction childAction in childActions)
{
bool result = DoMyThings(rootAction, childAction);
Console.WriteLine(String.Format("Processed '{0}' / '{1}': Result = {2}", rootAction.GetType().Name, childAction.GetType().Name, result));
}
}
}
If you need the Enums the action classes can be derived from them, but the solution becomes more bloated.

The first step could be that in every case you call a method.
case EnumRootAction.Type1:
switch(child){
case EnumChildAction.Ac1:
Type1_Ac1();
break;
The second step could be that you use a matrix of delegates instead of the function.
delegate bool DoMyThingsAction();
DoMyThingsAction[,] doMyThings;
public void InitializeDoMyThings()
{
doMyThings = new DoMyThingsAction[10, 10]; // number of actions and type
doMyThings[0, 0] = Type1_Ac1;
// and so on
}
To call it you can use
doMyThings[(int)root, (int)child];
If you don't like the cast to int in doMyThings call you can use a different structure and override the indexer.
Another option is to use reflection to get the method (I don't like it)
public bool DoMyThings(EnumRootAction root, EnumChildAction child){
return GetType().GetMethod(string.Format("{0}_{1}", root, child).Invoke(this);
}
EDIT
Looking at your program you should return false if there is not the method.
In case of matrix you can check if there is the function or not before call it, in case of reflection you can check if GetMethod returns null.

You could apply the Visitor Pattern. Your RootActions are Visitors and ChildActions are Elements. Here is the code, note how powerful of overloading in OOP:
List<RootAction_Visitor> visitors = new List<>();
visitors[EnumRootAction.Type1] = new RootAction1_Visitor();
visitors[EnumRootAction.Type2] = new RootAction2_Visitor();
List<ChildAction_Element> elements = new List<>();
elements[EnumChildAction.Ac1] = new ChildAction1_Element();
elements[EnumChildAction.Ac2] = new ChildAction2_Element();
elements[EnumChildAction.Ac3] = new ChildAction3_Element();
public void doMyThing(EnumRootAction root, EnumChildAction child) {
elements[child].accept( visitors[root] );
}
//=======================================================================
// Visitors
abstract class RootAction_Visitor {
public void visit(ChildAction1_Element childAction) { /*.. reject by default ...*/ }
public void visit(ChildAction2_Element childAction) { /*.. reject by default ...*/ }
public void visit(ChildAction3_Element childAction) { /*.. reject by default ...*/ }
}
class RootAction1_Visitor : RootAction_Visitor {
public override void visit(ChildAction1_Element childAction) {
// ... do something
}
public override void visit(ChildAction2_Element childAction) {
// ... do something
}
}
class RootAction2_Visitor : RootAction_Visitor {
public override void visit(ChildAction1_Element childAction1) {
// ... do something
}
public override void visit(ChildAction3_Element childAction3) {
// ... do something
}
}
//=======================================================================
// Elements
interface ChildAction_Element {
void accept(RootAction_Visitor visitor);
}
class ChildAction1_Element : ChildAction_Element {
public void accept(RootAction_Visitor visitor) { visitor.visit(this); }
}
class ChildAction2_Element : ChildAction_Element {
public void accept(RootAction_Visitor visitor) { visitor.visit(this); }
}
class ChildAction3_Element : ChildAction_Element {
public void accept(RootAction_Visitor visitor) { visitor.visit(this); }
}
Because your client and server communicate through network (inter-process communication). There's no way to ensure data sent by client is valid, we need to validate the data and reject wrong request. However, you should provide another service so client can know which combinations of actions are correct before requesting to your main service.
P/S: choosing between RootAction and ChildAction, which is Visitor, which is Element depends on how stable are they. If RootActions are unstable, i.e. new kinds of RootAction will come, then they should be Visitors.

Related

Chain of transformations based on generic types

I'm thinking about a chain, that will allow me to perform a set of transformations with data type changing from transformation to transformation. So far I've got something like this:
public abstract class TransformationStep<T, TY>
{
public abstract TY Execute(T input);
}
public class Times2<TY> : TransformationStep<int, TY>
{
public Times2(TransformationStep<int, TY> next)
{
Next = next;
}
public TransformationStep<int, TY> Next { get; set; }
public override TY Execute(int input)
{
var res = input * 2;
return Next.Execute(res);
}
}
public class ToString<TY> : TransformationStep<int, TY>
{
public ToString(TransformationStep<string, TY> next)
{
Next = next;
}
public TransformationStep<string, TY> Next { get; }
public override TY Execute(int input)
{
var res = input + "!!!";
return Next.Execute(res);
}
}
The only problem I see is the end chain type, where I can't convert T to TY.
public class End<T, TY> : TransformationStep<T, TY>
{
public override TY Execute(T input)
{
return input;
}
}
Do you have any solution? Also what do you think about this design and do you know any good materials on stuff like that?
It looks like you want transformations:
public abstract class TransformationStep<TIn, TOutput>
{
public abstract TOutput Execute(TIn input);
}
And if you want to just return input type, then it is possible to create another method with return type:
public abstract class TransformationStep<TIn, TOutput>
{
public abstract TOutput Execute(TIn input);
public abstract TIn ExecuteWithoutTransformation(TIn input);
}
Dataflow
If you want to connect chains of data into pipeline or graph, then you can use TransformBlock.
What is about Chain of Responsibility pattern?
As wiki says about "Chain of Responsibility pattern":
In object-oriented design, the chain-of-responsibility pattern is a
behavioral design pattern consisting of a source of command objects
and a series of processing objects.2 Each processing object contains
logic that defines the types of command objects that it can handle;
the rest are passed to the next processing object in the chain. A
mechanism also exists for adding new processing objects to the end of
this chain.
Your code looks similar, however, code and goal of chain responsibility pattern is slightly different. It does not make transformations, it gives object to the next processing object in the chain.
So one of the variations of code of chain of the responsibility pattern can look like this:
An abstraction of desired behaviour of chain of the responsibility pattern:
public abstract class MyHandler<T>
{
private MyHandler<T> Next { get; set; }
public virtual void Handle(T request)
{
Next?.Handle(request);
}
public MyHandler<T> SetNext(MyHandler<T> next)
{
Next = next;
return Next;
}
}
And let us imagine that we are publishing house and we want that each property of article should be validated.
So, concrete implemetations of handling article can look like this:
public class OnlyNewArticleValidationHandler : MyHandler<Document>
{
public override void Handle(Document document)
{
if (document.DateCreated.Year < DateTime.Now.Year)
{
throw new Exception("Only new articles should be published.");
}
base.Handle(document);
}
}
public class AuthorValidationHandler : MyHandler<Document>
{
public override void Handle(Document document)
{
if (string.IsNullOrWhiteSpace(document.Author))
{
throw new Exception("Author is required.");
}
base.Handle(document);
}
}
public class NameRequiredValidationHandler : MyHandler<Document>
{
public override void Handle(Document document)
{
if (string.IsNullOrWhiteSpace(document.Name))
{
throw new Exception("Name is required.");
}
base.Handle(document);
}
}
And ArticleProcessor would look like this:
public class MyChainAticleProcessor
{
public void Validate(Document document)
{
var handler = new NameRequiredValidationHandler();
handler.SetNext(new AuthorValidationHandler())
.SetNext(new OnlyNewArticleValidationHandler());
handler.Handle(document);
}
}
And it can be run like this:
new MyChainAticleProcessor().Validate(
new Document { Author = "Author 1", Name="Name 1" }
);

How to validate an item when it is added to the list in C#

I need to validate an item added to a list in C#. I've looked at this article: Validating lists in C#, but it isn't working.
returnModel.FileSystemItems.Add(new FileManagerFileSystemItem
{
Name = item.FolderName,
Key = item.FolderId.ToString(),
Key2 = "folder",
Key3 = key3,
IsDirectory = true,
HasSubDirectories = list.Any(a => a.ParentId == item.FolderId),
DateModified = DateTime.Now,
Size = 0,
Metadata = metadata,
Permissions = key3 == FileManagerFolderType.Private.ToString() ? GetPrivateFolderPermissions() : GetPublicFolderPermissions(hasFileManager)
});
So I want to make sure they set Key to an id or make sure Key2 is set to "Files" or "Folders"
I'm not trying to validate really the end-user, but validate to make sure the developer has set all the necessary properties when using the list.
Of course, I could add a Validate() method within the class to validate it after they are done adding to it, but then the developer would have to know to add that code at the end, which kind of defeats the purpose.
I tried to do the example here: https://stackoverflow.com/a/51523347/13698253, but it will never hit the breakpoint in the code.
Any ideas on how to solve this OR do I just need to add my own validation method at the end of the list that will make sure that the developer added everything properly.
This is not in a model validation for the model state of the controller. This is just in a normal class that might not be tied to MVC etc.
Thanks.
You can create your own custom List class which will throw an exception if the item being added is invalid:
public FileManagerFileSystemItemList : List<FileManagerFileSystemItem>
{
// edit: added TryAdd as per other's suggestions
// all this does is wrap the Add call in a try/catch block
// which would be enough to prevent unwanted exceptions
// but using Add alone would throw potentially useful exceptions
// for the developer to then deal with.
public bool TryAdd(FileManagerFileSystemItem item)
{
try
{
Add(item);
return true;
}
catch
{
return false;
}
}
new public void Add(FileManagerFileSystemItem item)
{
Validate(item);
base.Add(item);
}
private void Validate(FileManagerFileSystemItem item)
{
if (!Guid.TryParse(item.Key, out _))
throw new Exception("Key is not an id");
// ... and other validation
}
}
If however you wanted something more generic, you could put the validation into the class to be validated and have it implement an interface that can then be used as a constraint in a ValidatableList:
public interface IValidatable
{
bool IsValid { get; }
void Validate();
}
public class ValidatableList<T> : List<T> where T : class, IValidatable
{
public bool TryAdd(T item)
{
if (!item.IsValid)
return false;
base.Add(item);
return true;
}
new public void void Add(T item)
{
item.Validate();
base.Add(item);
}
}
public class FileManagerFileSystemItem : IValidatable
{
...
// rest of your class
...
public bool IsValid
{
get
{
try
{
Validate();
return true;
}
catch
{
return false;
}
}
}
public void Validate()
{
if (!Guid.TryParse(Key, out _))
throw new Exception("Key is not an id");
// ... and other validation
}
}
// Now your FileSystemItems property would be an instance of the new List class
...
ValidatableList<FileManagerFileSystemItem> FileSystemItems ...
...
The only potential issue I can see with the above is if the class you want a list of is not one you can modify to add in your validation. In this case you would need a separate validator class that handles this for your object which would look more like:
public interface IValidator<T> where T : class
{
bool IsValid(T item);
void Validate(T item);
}
public class FileSystemItemValidator : IValidator<FileManagerFileSystemItem>
{
public bool IsValid(T item)
{
try
{
Validate(item);
return true;
}
catch
{
return false;
}
}
public void Validate(T item)
{
if (!Guid.TryParse(item.Key, out _))
throw new Exception("Key is not an id");
// ... and other validation
}
}
// and the list class needs to know which class can validate its items
public class ValidatableList<T, TValidator> : List<T> where TValidator : class, IValidator<T>, new()
{
private readonly TValidator _validator;
public ValidatableList()
: base()
{
_validator = new TValidator();
}
public bool TryAdd(T item)
{
if (!_validator.IsValid(item))
return false;
base.Add(item);
return true;
}
new public void void Add(T item)
{
_validator.Validate(item);
base.Add(item);
}
}
// Now your FileSystemItems property would be an instance of the new List class
...
ValidatableList<FileManagerFileSystemItem, FileSystemItemValidator> FileSystemItems ...
...

Implementing FactoryPattern without using an Interface C#

I have a requirement of refactoring the code where I have multiple classes and the object of the classes need to be created dynamically depending upon the user request. Now the classes are all there and have no common methods within them that match each other. So I cannot add an interface to it and create a factory class that will return the interface reference referencing the actual class. Is there a way with generics or any other way to refactor this to be able to create objects dynamically. The approach we have now is that there is a main class where the object of each class is instantiated and all methods are being called. Can we implement a factory pattern without an interface or any solution to my scenario ? Please.
Adding sample code to explain the scenario.
public interface ITest
{
string TestMethod1(string st, int ab);
int TestMethod2(string st);
void TestMethod4(int ab);
float ITest.TestMethod3(string st);
}
public class Class1 : ITest
{
public string TestMethod1(string st, int ab)
{
return string.Empty;
}
public void TestMethod4(int ab)
{
throw new NotImplementedException();
}
public int TestMethod2(string st)
{
throw new NotImplementedException();
}
public float TestMethod3(string st)
{
throw new NotImplementedException();
}
}
public class Class2 : ITest
{
float ITest.TestMethod3(string st)
{
return float.Parse("12.4");
}
void ITest.TestMethod4(int ab)
{
throw new NotImplementedException();
}
public string TestMethod1(string st, int ab)
{
throw new NotImplementedException();
}
public int TestMethod2(string st)
{
throw new NotImplementedException();
}
}
public class Main
{
ITest test = null;
public ITest CreateFactory(TestType testType)
{
switch(testType)
{
case TestType.Class1:
test = new Class1();
break;
case TestType.Class2:
test = new Class2();
break;
}
return test;
}
}
enum TestType
{
Class1,
Class2
}
So, as in above, I can't have the interface because no common methods are in it. So what other solutions I can have, if I have an empty interface or abstract method, how will that help. Even if I put one common method in the interface and all classes implement it, since I am passing the reference to the interface, I can only access the common method from the interface reference.
My idea is to use something like the below, but not sure what the return type would or should be defined as.
public T CreateFactory(TestType testType)
{
switch(testType)
{
case TestType.Class1:
return GetInstance<Class1>("Class1");
case TestType.Class2:
return GetInstance<Class1>("Class2");
}
return null;
}
public T GetInstance<T>(string type)
{
return (T)Activator.CreateInstance(Type.GetType(type));
}
How do I define T here in the return is my concern and how can I invoke it, if anybody can help with that, then I think I am close to the solution.
Answer to my problem
public static T CreateFactory<T>()
where T: IFactory, new()
{
return new T();
}
I'm not saying totally understand the problem, but give it a shot...
Factory like class that you have:
class Factory
{
public static Visitable Create(string userInput)
{
switch (userInput)
{
case nameof(ClassA):
return new ClassA();
case nameof(ClassB):
return new ClassB();
default:
return null;
}
}
}
Types that you have to create:
class ClassA : Visitable
{
public void M1(){}
public override void Accept(Visitor visitor){visitor.Visit(this)}
}
class ClassB : Visitable
{
public void M2(){}
public override void Accept(Visitor visitor){visitor.Visit(this)}
}
Usage of the code:
var visitor = new Visitor();
var obj = Factory.Create("ClassA");
obj.Accept(visitor);
And the missing parts:
class Visitor
{
public void Visit(ClassA obj){ obj.M1(); } // Here you have to know what method will be called!
public void Visit(ClassB obj){ obj.M2(); } // Here you have to know what method will be called!
}
abstract class Visitable
{
public abstract void Accept(Visitor visitor);
}
This is called the Visitor pattern. If you know what methods need to be called Visitor.Visit than that is what you want.
I don't entirely understand your question but a basic assertion is wrong. I am concerned with your design given the basis of your question.
Regardless, my proposed solution:
You are saying that you don't have a common object (indirect, directly you stated: "I can't have the interface because no common methods are in it."
object is the common element.
I don't condone this but you could create a factory object that just returned object as the data type. The problem with this is you then have to cast it after the object creation which you may not mind...
internal class MyFactory
{
internal object CreateItem1() { return ...; }
internal object CreateItem2() { return ...; }
internal object CreateItem2(ExampleEnum e)
{
switch(e)
{
case e.Something:
return new blah();
default:
return new List<string>();
}
}
}

C# specialize generic class

Is it possible to do the following specialization in C#? I can do this in C++ but do not understand how to achieve the same result in C#.
class GenericPrinter<T>
{
public void Print()
{
Console.WriteLine("Unspecialized method");
}
}
class GenericPrinter<int>
{
public void Print()
{
Console.WriteLine("Specialized with int");
}
}
Added:
The problem with suggested GenericPrinterInt solution is that I need to explicitly create it. new GenericPrinter<int> will still print Unspecialized method.
What I want is to use this GenericPrinter from another generic class without the knoledge is T equal to int or something else.
I guess the closer you could get in C# would be:
class GenericPrinter<T>
{
public virtual void Print()
{
Console.WriteLine("Unspecialized method");
}
}
class IntPrinter : GenericPrinter<int>
{
public override void Print()
{
Console.WriteLine("Specialized with int");
}
}
Otherwise, the answer is, you can't specialize in C#.
As Lyubomyr Shaydariv said in his comment:
C++ templates are not .NET generics. You can't.
From your edit I guess you will have some type checking to make.
You can do this with a dictionary for example.
class GenericPrinter<T>
{
private Dictionary<Type, Action> _actions
= new Dictionary<Type, Action>()
{
{ typeof(int), PrintInt }
};
public virtual void Print()
{
foreach (var pair in _actions)
if (pair.First == typeof(T))
{
pair.Second();
return ;
}
Console.WriteLine("Unspecialized method");
}
public virtual void PrintInt()
{
Console.WriteLine("Specialized with int");
}
}
Like you can see, you will have to make a method for each type, you want to handle. And you may also encounter some issues when you will try to manipulate T as int. Since, T is really generic (it hasn't any constraint), it will more likely act as an object in your code (not at runtime) you will have to cast it like that (int)(object)yourTVariable in your methods where you are sure that T is an int.
But for this part, I guess some of my peers, will have a better answer than me to give to you.
If it's just about displaying which type you are using:
public virtual void Print()
{
Console.WriteLine($"Specialized with {typeof(T).Name}");
}
But you won't have the unspecialized message anymore (and if you think about it, you can't have a GenericPrinter instantiated without specifying its type. Then it makes no sense to have a method that displays "unspecialized", you will always have a specified type)
Anyway, the answer is still the same, you can't specialize a generic in C#.
It isn't possible in C#.
You can use inheritance instead:
class GenericPrinter<T>
{
public virtual void Print()
{
Console.WriteLine("Unspecialized method");
}
}
class GenericPrinterInt : GenericPrinter<int>
{
public override void Print()
{
Console.WriteLine("Specialized with int");
}
}
According to the updated question, I can only suggest you the following approach. You could create a static factory method in which you can check the type of T and instantiate an appropriate specialized class if the type matches the criteria:
class GenericPrinter<T>
{
public static GenericPrinter<T> Create()
{
if (typeof(int).IsAssignableFrom(typeof(T)))
return (GenericPrinter<T>)(object)new GenericPrinterInt();
if (typeof(double).IsAssignableFrom(typeof(T)))
return (GenericPrinter<T>)(object)new GenericPrinterDouble();
// Other types to check ...
return new GenericPrinter<T>();
}
public virtual void Print()
{
Console.WriteLine("Unspecialized method");
}
}
class GenericPrinterInt : GenericPrinter<int>
{
public override void Print()
{
Console.WriteLine("Specialized with int");
}
}
class GenericPrinterDouble : GenericPrinter<double>
{
public override void Print()
{
Console.WriteLine("Specialized with double");
}
}
Some other generic class:
class SomeGenericClass<T>
{
public readonly GenericPrinter<T> Printer = GenericPrinter<T>.Create();
}
Usage sample:
var intClass = new SomeGenericClass<int>();
intClass.Printer.Print();
// Output: Specialized with int
var doubleClass = new SomeGenericClass<double>();
doubleClass.Printer.Print();
// Output: Specialized with double
var stringClass = new SomeGenericClass<string>();
stringClass.Printer.Print();
// Output: Unspecialized method
You can do it but you need to move your code into lambda expressions
or some flavor of lambdas.
It's not pretty but is fast ( no lookups ) and has the specialization.
You can tailor this to your needs
Cummon Microsoft we shouldn't have to do this.
How many improvements to .Net and no specialization.
public class GenericPrinter<T>
{
public static GenericPrint()
{
T thing = default(T)
switch(thing)
{
case int ival:
_Print = ()=>
{
Console.WriteLine("Specialized Int print Code");
};
break;
default:
_Print = ()=>
{
Console.WriteLine("Some generic print code");
};
break;
}
}
// will be unique for every type of T
public static Action _Print=null;
public void Print()
{
_Print();
}
}
Use would be the same
var printer = new GenericPrinter<int>();
printer.Print();

Refactoring a method for specific clients

Methods specific for customers:
I try to refactore a code, where are a lot of logic for specifi customer:
public void SendDocumentsToCustomer(List<Case> cases)
{
foreach(var case in cases)
{
if(case.CustomerId==123)
{
if(case.Type==1 || case.Type==2)
{
SendDocumentsToCustomer123(case)
}
else if(case.CustomerId==456)
{
if(case.Type==1 || case.Type==3)
{
SendDocumentsToCustomer456(case);
}
}
else if(case.CustomerId==768)
{
if(case.Type==2)
{
SendDocumentsToCustomer456(case);
}
else
{
SendDocumentsToCustomer(case);
}
}
}
The list of specific customer will grow, and the conditions will be modified as well. I will have a generic solution, but maybe code like this with method DoItForClient123 is not a bad solution and I should leave it like that and goint this way introduce methods like CanDocumentsBeSendToClient123 and so on?
I will be very gratefull for some input
To separate logic for each specific customer I would use such code:
abstract class DocumentSender //Base class for all document sending components
{
public abstract bool CanSend(Case #case); // Check if sender can send the document
public abstract void SendDocument(Case #case); // Send the document
}
class DefaultDocumentSender : DocumentSender
{
public override bool CanSend(Case #case)
{
return true; //Can process all requests
}
public override void SendDocument(Case #case)
{
// Do something
}
}
class Customer123DocumentSender : DocumentSender
{
public override bool CanSend(Case #case)
{
return #case.CustomerId == 123; //Specific case
}
public override void SendDocument(Case #case)
{
if(#case.Type==1 || #case.Type==2)
{
// Do something different
}
}
}
//Separate class for getting the correct sender
class CaseSenderFactory
{
readonly List<DocumentSender> _senders = new List<DocumentSender>();
public DocumentSenderFactory()
{
//Initialize the list of senders from the most specific.
_senders.Add(new Customer123DocumentSender());
// Add more specific cases here
_senders.Add(new DefaultDocumentSender()); //Last item should be the default sender
}
public DocumentSender GetDocumentSender(Case #case)
{
//At least one sender needs to satisfy the condition
return _senders.First(x => x.CanSend(#case));
}
}
You then can use the senders like this:
var factory = new DocumentSenderFactory();
foreach(var #case in cases)
{
var sender = factory.GetDocumentSender(#case);
sender.SendDocument(#case);
}
I think it would be a good ideea to make something like this:
The ideea is if the code is really specific to some of the Customers then you could make a class for them. If the code for specific customers somehow related but combined in a diferent way then you should take a loot at DecoratorPattern(mabye it helps)
class Customer
{
public abstract SendDocumentsTo(Customer c);
}
class SpecificCustomerA
{
public overwrite SendDocumentsTo(Customer c)
{
if (c is SpecificCustomerB)
{
//Logic here
}
}
}
class SpecificCustomerB { ... }

Categories