解耦第三方库的设计模式

5

我正在尝试解耦第三方库的抽象类。我希望暴露一个新的抽象类,而不是库提供的类,让用户使用。
我最初尝试使用适配器,但仍需要在适配器类中导入第三方库。

我添加了下面的代码,解释了我的方法。

   // 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 
       }
   }

任何指导关于应该遵循哪种设计模式在这里将非常有帮助。

3
我最初尝试使用适配器,但这仍然需要在适配器类中添加第三方库的导入。看起来还不错,因为适配器不仅包括您的应用程序端,还包括第三方端。您能否解释一下这一点? - GauravJ
@GauravJ 是的,正如你所说的,适配器会在暴露的类中引入第三方。我试图避免这种情况。我的目标是仅公开一个独立的抽象类,它不依赖于第三方库。我还尝试使用桥接模式,但不太确定如何在泛型中实现解耦。也许我的整体方法在这里解耦第三方库是错误的,正确的方法是采用适配器或外观,并不担心解耦第三方。 - x_____x
7
你应该将第三方依赖推到应用程序的边缘。声明接口并使你的内部类依赖于这些接口。我认为这样做没有问题。适配器模式或桥接模式可以实现这一点,但是你的应用程序仍然会有类依赖关系。你的核心类不会知道第三方库(你的适配器或桥接器会知道)。如果你想要从应用程序中删除jar依赖项,那么你需要使用类似于java.util.ServiceLocator的东西,但我怀疑这是否符合你的使用情况。 - GauravJ
1个回答

1

我同意GuaravJ的回答,您可以隔离第三方依赖项并使用适配器或桥接模式从那里调用第三方库。我认为这将是一种足够解耦的解决方案。

然而,您似乎想要删除import,因此依赖关系呢?

作为替代方案,如何在ThirdParty类上实现反射

Java与反射导向编程兼容。这使您可以在运行时动态地检查和检查类并调用它们的方法。它将消除对于ThirdParty类的依赖和import语句。

一般来说,使用反射,您必须定位类并检查其方法。在这种情况下,我假设您了解ThirdPartyClass中的doAction()方法。

遵循您代码摘录思路的简单Java反射示例:

不使用反射

// 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();

使用反射
// 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);

更多阅读和注释


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接