vendredi 22 décembre 2017

Design pattern to add special handling for external lib class

I'm using Foo class from external library. Foo contains several methods and all of them return FooResult enum.

I need to do two things:

  • provide mock implementation of Foo
  • add special handling (some logging, alert via mail) depends on FooResult returned from each Foo method
  • be able to easly switch between mock and real implementation

Foo do not extends any interface that I can use already to provide mock implementation. My current implementation provide solution for point 1 and 3 but I find it pretty ugly. What I have done is: I have extended Foo like FooMock extends Foo and @Override each method, then I can just use Foo anywhere and switch implementation by providing different bean (using SpringBoot and ConditionalOnProperty). But I'm missing a special handling for both implementations.

I could just add some kind of handler for each method where I'm using Foo but this would be ugly as hell and break the DRY rule.

So I'm looking for some pretty design pattern to solve this problem. I thought about proxy - however in proxy Foo should implement the same interface as FooProxy right? Any other ideas?

My current implementation:

Foo class:

public class Foo {
    //fields
    //constructor
    FooResult methodA(){
        //impl
    }

    FooResult methodB(){
        //impl
    }
}

FooMock class:

public class FooMock extends Foo {
    //fields
    //constructor
    @Override
    FooResult methodA(){
        //mock impl
    }
    @Override
    FooResult methodB(){
        //mock impl
    }
}

ClassWhereImUsingFoo class:

public class ClassWhereImUsingFoo{

     private Foo foo;

     //other fields
     @Autowired
     public ClassWhereImUsingFoo(Foo foo){
         this.foo = foo;
     }

     public void sampleMethodUsingFoo(){
         FooResult res = foo.methodA();
         //special handling
         if(res == A){
               //send some alert
         } else if (res == B) {
               //do logging
         } else {
               //do something else
         }
     } 

     //other methods using foo
 }

Aucun commentaire:

Enregistrer un commentaire