How to 'wrap' two classes with identical methods?

前端 未结 6 746
萌比男神i
萌比男神i 2021-02-15 10:50

I have to handle two classes with identical methods but they don\'t implement the same interface, nor do they extend the same superclass. I\'m not able / not allowed to change t

6条回答
  •  梦如初夏
    2021-02-15 11:30

    You can use a dynamic proxy to create a "bridge" between an interface you define and the classes that conform but do not implement your interface.

    It all starts with an interface:

    interface Something {
      public String getValueOne();
      public void setValueOne(String valueOne);
      public String getValueTwo();
      public void setValueTwo(String valueTwo);
    }
    

    Now you need an InvocationHandler, that will just forward calls to the method that matches the interface method called:

    class ForwardInvocationHandler implements InvocationHandler {
      private final Object wrapped;
      public ForwardInvocationHandler(Object wrapped) {
        this.wrapped = wrapped;
      }
      @Override
      public Object invoke(Object proxy, Method method, Object[] args)
          throws Throwable {
        Method match = wrapped.getClass().getMethod(method.getName(), method.getParameterTypes());
        return match.invoke(wrapped, args);
      }
    }
    

    Then you can create your proxy (put it in a factory for easier usage):

    SomethingA a = new SomethingA();
    a.setValueOne("Um");
    
    Something s = (Something)Proxy.newProxyInstance(
        Something.class.getClassLoader(), 
        new Class[] { Something.class }, 
        new ForwardInvocationHandler(a));
    
    System.out.println(s.getValueOne()); // prints: Um
    

    Another option is simpler but requires you to subclass each class and implement the created interface, simply like this:

    class SomethingAImpl extends SomethingA implements Something {}
    class SomethingBImpl extends SomethingB implements Something {}
    

    (Note: you also need to create any non-default constructors)

    Now use the subclasses instead of the superclasses, and refer to them through the interface:

    Something o = new SomethingAImpl(); // o can also refer to a SomethingBImpl
    o.setValueOne("Uno");
    System.out.println(o.getValueOne()); // prints: Uno
    

提交回复
热议问题