CCC
CCC

Reputation: 2761

POJOs, generics and extending them

I have a POJO that returns some value, but now that value could be of a different type:

public class ContainerA {
    String value;
    public ContainerA(String value) {
       this.value = value;
    }
    public String getValue() {
       return value;
    }
    //some more methods
}

So I wanted to just replace it with this other one, but the refactoring effort would be just too great:

public class ContainerA<T> {
    T value;
    public ContainerA(T value) {
       this.value = value;
    }
    public T getValue() {
       return value;
    }
    //some more methods
}

And to avoid that large refactoring I was thinking that I could have something like this:

public interface Container<T> {
    public T getValue() {
    //some more methods
}

public class ContainerA implements Container<String> {
    String value;
    public ContainerA(String value) {
       this.value = value;
    }
    public String getValue() {
       return value;
    }
    //implementation of those other methods
}

But since most of those POJO classes will look pretty much the same and there are a bunch of other methods, so I was wondering why this would be problematic:

public class Container<T> {
    T value;
    public Container(T value) {
        this.value = value;
    }
    public T getValue() {
        return value;
    }
    //some other methods
}

public class ContainerA extends Container<String> {
    public ContainerA(String value) {
       super(value);
    }
}

Again, the idea is to add generics support and avoid the large refactor. Is there a better approach? is any of the above ok? why?

Upvotes: 0

Views: 1260

Answers (3)

weston
weston

Reputation: 54801

This option:

public class ContainerA extends Container<String> {
    public ContainerA(String value) {
       super(value);
    }
}

Is a perfectly reasonable step in refactoring, but it's not the end goal as you don't want two ways to achieve the same thing, particularly as they are not 100% compatible.

e.g. if you have a method like so: method(Container<String> container) then that will accept a ContainerA, but the reverse is not true; method(ContainerA container) won't accept a Container<String>

So what you can do for now is you can mark the old type as deprecated and take your time completing the refactor, safe in the knowledge that, as the old code descends from the new code it is perfectly safe to use and that people will know which of the two implementations they should be using in new code:

/**
 * @deprecated Use {@link Container<String>}
 */
@Deprecated
public final class ContainerA extends Container<String> {

Upvotes: 1

Klaymen
Klaymen

Reputation: 83

It really depends on your future plans with Container:

If you don't plan on reusing and extending the methods and properties of Container there's really no use inheriting from it*. Use an interface if you want polymorphism (you might want to keep the simple generics if you don't). An interface will provide you with capabilities similar to the ones you get from inheritance (such as polymorphism) without asking you to extend anything.

Furthermore, if I'm working in your team, when I see ContainerA, I'm not sure why to use it when my project already contains Container<>.

Upvotes: 0

Nesan Mano
Nesan Mano

Reputation: 2166

I would recommend you to use an generic interface so it can be implemented as per your need.Also interfaces are good when you don't have an initial idea of your would be implementations.Another pro of using interface is you can later add methods which is useful for continuous development.

public interface MyInterface<T> {
   public void method(T object);
}

public class Car implements MyInterface<Engine> {
    public void method(Engine object) {
    }
}

Upvotes: 0

Related Questions