質問

Case: Several methods with same params validation inside, like:

public Response method1(...params...)
{
    if (someCondition)
    {
        //do some stuff with side effects
        ...
        return Response1;
    }
    if (someCondition2)
    {
        //do another stuff with side effects
        ...
        return Response2;
    }
    if (someCondition3)
    {
        //do another stuff with side effects
        ...
        return Response3;
    }
    // Do something
    return Response4;
}

and

public Response method2(...params...)
{
    if (someCondition)
    {
        //do another stuff with side effects
        ...
        return Response1;
    }
    if (someCondition2)
    {
        //do another stuff with side effects
        ...
        return Response2;
    }
    if (someCondition3)
    {
        //do another stuff with side effects
        ...
        return Response3;
    }
    // Do something 2
    return Response4;
}

Etc.......... How Can i avoid duplication without throwing exception?

UPD: I try to explain why it is not duplicate of Style for control flow with validation checks : In this case in both functions after "someCondition" validation we have some code with side effects in function, not just return response, so i cant just make some method (Specification pattern) that do validation and return response because of additional logic after validate param.

役に立ちましたか?

解決

My suggestions, in my personally-recommended order:

Option 1: Assuming those primitives are often used together, wrap them all in an object that models their collective value to the problem domain, and perform the validation in that class. If you can, make it a struct, so you don't require null checks in both methods.

Option 2: Handle the validation in calling code that is in a higher tier, layer, or level of abstraction, assuming that reduces the duplication

Option 3: Using Aspects (aop).

Aspect-oriented programming specializes in handling cross-cutting concerns that object-oriented programming can sometimes struggle with, such as logging, validation, or error handling. It works through the use of 'Aspects' which are pieces of code that can be applied to multiple methods, classes, or even assemblies. For example, in your case, you might have a 'ParameterValidationAspect' that, when applied to a method, validates the method arguments and determines whether the method should be executed or if another value should be returned instead.

The code can vary greatly based on the implementation, but a common pattern is to have an attribute that is applied to a parameter, method, class, or assembly, similar to this sample:

[LogMethodEntryAndExitAspect]
public void Method1()
{
  // no code in here, but aspect logs before method is entered and after method exits
}

[ValidateParametersAspect<ResponseType>]
public ResponseType Method2(string p1, int p2)
{
   //ValidateParameters aspect will perform the validation and return the appropriate response.

   //Other logic
   return new ResponseType();
}

The exact mechanism aspect-oriented programming uses to insert logic into methods can vary, based on the implementation you go with. Generally, there's three mechanisms an aop library uses :

  1. Inserting code after compilation by modifying the byte or ilsm code (C#'s PostSharp uses this).
  2. Intercepting method calls with a wrapper object.
  3. Using reflection to modify the class at runtime (can overlap a bit with #2)

Some implementations might provide hooks for you to tap into, like 'PreMethodExecute', 'MethodExecution', 'OnException', etc.

I enjoy the concept of Aop, but its complexity can be substantial, especially in the beginning of the learning curve. It's difficult for a single developer to introduce it into a system, and pursuing this type of solution should have buy-in across your teams.

ライセンス: CC-BY-SA帰属
所属していません softwareengineering.stackexchange
scroll top