I have code that I want to modify applying the Chain of Responsibility (CoR) pattern, but I have a doubt about performance if I have many successors. First, this is the code without CoR:
public class OperationService
{
public Response Exec_Operation_1(Data data)
{
Operation_1 op = new Operation_1();
return op.ExecOperation();
}
public Response Exec_Operation_2(Data data)
{
Operation_2 op = new Operation_2();
return op.ExecOperation();
}
}
public class Operation_1
{
private Data _data;
public Operation_1(Data data)
{
this._data = data;
}
public Response ExecOperation()
{
//process data. So much code. Many instantiations.
//Many references to other assemblies.
//serialize/deserialize xml. Call webservices.
return new Response();
}
}
//Operation_2 class seems like Operation_1 class...
Well, really there are many Operation classes: Operation_3,....Operation_N, maybe between 11 and 15 classes, but in this moment there are only Operation_1 and Operation_2. If I want to add Operation_3, then I must update the OperationService class adding a new method: Exec_Operation_3(Data data).
I see that all methods return the same type (Response) and receive as a parameter the same type (Data), also methods of Operation_1 and Operation_N will have the same signature, so I think I can rewrite the code this way: (Solution 1)
public class OperationService
{
public Response Exec_Operation(Data data)
{
OperationCaller caller = new OperationCaller();
return caller.ExecOperation(data);
}
}
public class OperationCaller
{
public Response ExecOperation(Data data)
{
IOperation unknownOperation = new UnknownOperation();
IOperation operation_2 = new Operation_2(unknownOperation);
IOperation operation_1 = new Operation_1(operation_2);
return operation_1.ExecOperation(data);
}
}
public interface IOperation
{
bool CanExecute(Data data);
Response ExecOperation(Data data);
}
public class Operation_1:IOperation
{
private IOperation _succesor;
public Operation_1(IOperation succesor)
{
this._succesor = succesor;
}
public CanExecute(Data data)
{
return data.OperationType.equals("1");
}
public Response ExecOperation(Data data)
{
if(this.CanExecute)
{
//process data. So much code. Many instantiations.
//Many references to other assemblies.
//serialize/deserialize xml. Call webservices.
return new Response();
}
else
{
return this._succesor.ExecOperation(data);
}
}
}
//Other IOperation implementations seems like this Operation_1.
If you see I'm applying CoR pattern, this way I will not have to modify the OperationService class when I add a new Operation_X class, I will have to update the OperationCaller class only.
But in this solution I only modify the class Operation_1 (and Operation_2,..., Operation_N) but this class have so much code that reading is a little difficult so I think that it's better to create another class to use CoR and create an instance of Operation_1,..,Operation_N in that class, like this: (Solution 2)
public class OperationCaller
{
public Response ExecOperation(Data data)
{
IOperation unknownOperation = new CoRUnknownOperation();
IOperation operation_2 = new CoROperation_2(unknownOperation);
IOperation operation_1 = new CoROperation_1(operation_2);
return operation_1.ExecOperation(data);
}
}
public interface IOperation
{
bool CanExecute(Data data);
Response ExecOperation(Data data);
}
public class CoROperation_1:IOperation
{
private IOperation _succesor;
public Operation_1(IOperation succesor)
{
this._succesor = succesor;
}
public CanExecute(Data data)
{
return data.OperationType.equals("1");
}
public Response ExecOperation(Data data)
{
return (this.CanExecute) ? new Operation_1().ExecOperation(data);
: this._succesor.ExecOperation(data);
}
}
In this last solution I have not modified Operation_1, I have only created a layer to decouple OperationService (it's the goal).
But I think that Operation_1 instance -in this last solution- or IOperation instances -in the first solution- are a bit heavy objects and OperationCaller creates many of them so I have a doubt about this, I don't know if this implementation/solution will have performance issues.
What do you think. I will have performance issues using CoR in this case? if not, What solution is better the first (Solution 1) or the last (Solution 2)?.