'Access to equal class from a different source

Imagine having two identical classes from a different external source (.jar). Those two classes share nothing in common ie don't extend or implement same base class/interface. They do the same work or very similar but since they share nothing in common so one can not use generics very effectively. One ends up with a lot of duplicated code when using those two classes.

Is there any elegant way to avoid that without involving reflection?

Update: Classes have same name and same methods with same arguments from a different package.

Example:

import com.v1.BuilderFactory;
import com.v1.Foo;

class Builder1 {
    private final BuilderFactory builderFactory;

    Builder1(BuilderFactory builderFactory) {
        this.builderFactory = builderFactory;
    }
    Foo doStuff(Request request) {

        builderFactory.doStuff();
        return builderFactory.build();
    }
}

… and …

import com.v2.BuilderFactory;
import com.v2.Foo;

class Builder2 {
    private final BuilderFactory builderFactory;

    Builder2(BuilderFactory builderFactory) {
        this.builderFactory = builderFactory;
    }
    Foo doStuff(Request request) {

        builderFactory.doStuff();
        return builderFactory.build();
    }
}


Solution 1:[1]

Whoops.

When I first wrote this, I failed to notice that the Foo objects being returned by the method were of two different types from two different packages.

This means the original problem statement involves entirely separate code, different types, apples and oranges. No point in trying to join these disparate types.

I’ll leave the code in place below as it may be of interest to some in a similar situation. But this code does not properly solve the Question’s problem. If there were only a single type of Foo, then this code would have solved the problem.


As noted in your Question, your scenario precludes using the type system of Java directly. This means you cannot use polymorphism to dispatch automatically to the appropriate factory’s method. So we need to manually dispatch.

You will need to write redundant code that addresses each of the two separate types. However, you can wrap that code into a single new class. That new class contains an instance of either one type or the other. The benefit is that all the calling code can remain blissfully ignorant of the fact that there are alternative types implementing the functionality. The calling code gets an object of the wrapper, and the wrapper internally dispatches to one type or the other.

Define a wrapper class that contains an instance of either.

class BuilderWrapped
{
    // Only *one* of these two member fields will ever be populated. The other remains `null`. 
    private final com.v1.BuilderFactory builderFactory1;
    private final com.v2.BuilderFactory builderFactory2;

    // Constructors
    // We have a pair of constructors, one for each of the two types that we wrap.

    BuilderWrapped( com.v1.BuilderFactory f ) 
    {
        this.builderFactory1 = Objects.requireNonNull( f ) ;
    }

    BuilderWrapped( com.v2.BuilderFactory f ) 
    {
        this.builderFactory2 = Objects.requireNonNull( f ) ;
    }

    // Logic
    Foo doStuff( Request request ) {
        if ( Objects.nonNull( this.builderFactory1 ) { … use that factory to return a `Foo` object … }
        else if ( Objects.nonNull( this.builderFactory2 ) { … use that factory to return a `Foo` object … }
        else { … throw exception because this case should be impossible (defensive programming) … }
    }

}

Usage starts with instantiating our BuilderWrapped code.

BuilderWrapped bw = new BuilderWrapped( new com.v2.BuilderFactory() ) ; 

Pass bw to some calling code which can then call the Foo doStuff( Request request ) method which in turn calls upon the logic implemented in our contained com.v2.BuilderFactory object’s Foo doStuff( Request request ) method.

Foo foo = bw.doStuff( someRequest ) ;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1