Search code examples
c#refactoringstrategy-pattern

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


Solution

  • 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);
    }