Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design pattern to decouple from third party lib

I am trying decouple a third party library's abstract class. I want to expose a new abstract class which will be exposed to the users rather than the library provided class.
I initially tried using an adapter but that stills add the import for the third party lib in the adapter class.

I added code below explaining my new approach.

   // third party lib
    abstract class ThirdParty<S> { 
       public abstract S doAction(S s);
    }
    // my goal here is to expose a different abstract class which is    decoupled from third party lib
    // exposed to other modules, rather than exposing the third party lib
    abstract class ExposedAbstractClass<S> {
        public abstract S doAction(S source);
        // get hold of type using guava lib
        private final TypeToken<S> typeToken = new TypeToken<S>(getClass()) { };
        public Class<S> getSourceClass() { return (Class<S>) typeToken.getClass()
    }

  // internal class
   class Builder<S> extends ThirdPartyLib<S> {
       ExposedAbstractClass exposed;
       public Builder(ExposedAbstractClass exposed) {
         this.exposed = exposed;
       }
       @Override
       public S doAction(S s) {
         return (S) exposed.doAction(s);
       }
   }
   //my approach breaks here when i try to invoke builder 
   class InvokeThirdParty {
       public void invoke (ExposedAbstractClass exposed) {
         Class type = exposed.getSourceClass();
         Builder<type> builder = new Builder(exposed); //doesn't work since Class is runtime type, and T is compile time type 
       }
   }

Any guidance in terms of which design pattern to follow here would be very helpful.

like image 728
x_____x Avatar asked Nov 09 '22 02:11

x_____x


1 Answers

I agree with GuaravJ answer, you could isolate the third party dependency and use an Adaptor or Bridge pattern to invoke the third party library from there. I believe this would be an adequate decoupled solution.

However, it would seem your intent is to remove the import, hence the dependency?

As an alternative, how about implementing Reflection on the ThirdParty class?

Java is compatible with Reflection-oriented-programming. This lets you inspect and examine classes and invoke their methods dynamically at runtime. It would eliminate the dependency and the import statement for the ThirdParty class.

In general terms, with Reflection, you have to locate the class and inspect its methods. In this case I'm assuming knowledge of the doAction() method from ThirdPartyClass.

A simple Java reflection example following the idea of your code excerpt:

Not using reflection

// import ThirdPartyLibrary statement somewhere here

// Instantiating object with concrete class that implements methods from ThirdParty. From your code now, it would be "Builder".
ThirdParty<S> thirdPartyObject = new ThirdPartyImp<S>();

// Invoking doAction method which returns an S object    
S foo = thirdPartyObject.doAction();

Using reflection

// Inspect the class finding it using its path and instantiating an object
ThirdParty<S> thirdPartyObject = Class.forName("classpath.to.ThirdPartyImp").newInstance(); // Using a concrete class to instantiate.

// Finding the doAction method. This is assuming we have knowledge that a method with this name exists. Reflection could go as deep as not knowing the methods and having some control structure inspecting them.
Method doAction = thirdPartyObject.getClass().getDeclaredMethod("doAction", new Class<?>[0]);

// Do action is invoked and it returns an object S.
S foo = thirdPartyObject.invoke(thirdPartyObject);

Further reading and notes

  • Oracle Java official documentation on reflection
  • Java Reflection example tutorial
  • Wikipedia Reflection (Computer Science) definition and examples
like image 161
Santiago Varela Avatar answered Nov 14 '22 21:11

Santiago Varela