Java – Refactoring two classes from third-party library that could have extended a base class

javarefactoringthird-party-libraries

I have two Classes, with very similar behaviors, both from a third party library.
Both needs to be populated with some value object and sent to specific queues in order for logging. Please note both of them does not have a common parent.

I am scratching my head to find out ways to refactor this.
Here is the sceanrio.

Class 1 : Apple
Class 2 : Orange

Unfortunately, Apple and Orange are not child classes of Fruit
And I can not change them to extend a base class.
Constructors of Apple and Orange have different signatures.

Current code:

if(isApple){
    Apple apple = new Apple(....);
    apple.setColor(Color.RED);
    apple.setPrice(10);
    apple.setCount(1000);

    AppleMQObject applMQObject = new AppleMQObject(apple);
    Producer appleProducer = Factory.create("apple-producer");
    appleProducer.send(applMQObject);
}else{
    Orange orange = new Orange(...);
    orange.setColor(Color.ORANGE);
    orange.setPrice(30);
    orange.setCount(100);
    OrangeMQObject oMQObject = new oMQObject(orange);
    Producer orangeProducer = Factory.create("orange-producer");
    orangeProducer.send(orangeMQObject);
}

I can move the MQ code out to a common method. But how to handle the apple/orange situation.

Best Answer

This is a refinement of @user2670177 answer:

If the function signatures of both are nearly the same it might be easier to use inheritance instead of composition.

Given you have Oranges and Appels you want to process

class Orange {
    public void setColor(Color color){}
    public void setPrice(int euroCents){}
    public void setCount(int numberOfItems){}
}

class Apple {
    public void setColor(Color color){}
    public void setPrice(int euroCents){}
    public void setCount(int numberOfItems){}
}

You can define a common interface for both

interface MyFruitInterface{
    void setColor(Color color);
    void setPrice(int euroCents);
    void setCount(int numberOfItems);
}

and attach the interface to the inherited class

class MyOrangeImpl extends Orange implements MyFruitInterface {
} 

class MyAppleImpl extends Apple implements MyFruitInterface {
} 

Now your common code MQObject can handle both:

class MQObject {
    private MyFruitInterface fruit;
    MQObject(MyFruitInterface fruit) {
        this.fruit = fruit;
    }

    void setPriceColorCount(int euroCents, Color color, int numberOfItems) {
        fruit.setPrice(euroCents);
        fruit.setColor(color);
        fruit.setCount(numberOfItems);
    }
}

void testMQ() {
    MQObject applMQObject = new MQObject(new MyAppleImpl());
    MQObject orangeMQObject = new MQObject(new MyOrangeImpl());
}