1

I have two classes with identical implementations but different names. They are generated and I'm not able to modify them:

public class Foo {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class Bar {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

I need to populate these classes with data, and since they are identical would prefer to do it with a single class or reference, then cast to (or hopefully the solution is more elegant) the Foo or Bar as needed. Conceptually:

FooOrBar fob = ????;   
fob.setName("XYZ");

Foo f = fob.(???);
Bar b = fob.(???);

I've looked into generics, but it appears that is for when you truly don't know what Class you will be operating on. Is it possible for me to have some type of Class or reference that achieves this?

July 26 EDIT:

Apologies if it's bad form for follow ups like this, I can post new if need be. I'm in the process of implementing Tomasz's Adapter pattern but my final step differs from his. I have a need for conditional assignment of the interface object. The below is what I have and I get no errors or warnings on it so far, but I'm wondering if this isn't good practice for some reason? Perhaps I should use reflection or generics to determine the class for the interface? This will be in a method that only my code will call and I will know the condition. I've searched on conditional interface assignment but haven't found much.

FooOrBar fob;  //interface

if (condition true) {

    fob = new FooAdapter();  //FooAdapter implements FooOrBar
} else {
    fob = new BarAdapter();  //BarAdapter implements FooOrBar
}

fob.setName("XYZ");
user640118
  • 703
  • 12
  • 24
  • Write a superclass and let Foo, Bar extend it (or) write an interface and let Foo/Bar implement it. – kosa Jul 25 '12 at 17:51
  • 1
    I agree with thinksteep, but if you're not able to modify the classes to get rid of the duplication, I'm guessing you can't modify them to implement an interface. Are the classes really identical and, if so, why have they been created that way? – Bobulous Jul 25 '12 at 17:53
  • The classes are identical, they were created through wsdl consumption from a target system that I can't modify the wsdl on. The target system generates separate messages for a resource create and update, but it's the exact same data. – user640118 Jul 25 '12 at 18:02
  • thx all. I was hoping I wouldn't have to re-implement each method, but it doesn't look like I can get away from that. I'll give these a try and come back to accept. – user640118 Jul 25 '12 at 18:27

4 Answers4

2

What you are looking for is called and is not supported in Java. Try dynamic languages like and .

In Java, assuming you can't modify Foo and Bar, you'll need an Adapter pattern. First create an abstraction over Foo and Bar:

public interface FooOrBar {
    String getName();
    void setName(String name);
}

And have two adapters like these (BarAdapter is almost the same):

public class FooAdapter implements FooOrBar {

    private final Foo foo;

    public FooAdapter(Foo foo) {
        this.foo = foo;
    }

    public String getName() {
        return foo.getName();
    }

    public void setName(String name) {
        foo.setName(name);
    }

}

Now you can say:

FooOrBar fob = new FooAdapter(foo);
FooOrBar fob2 = new BarAdapter(bar);

fob.setName("XYZ");

I'll leave extracting the actual value to you (do you really need it?)

Tomasz Nurkiewicz
  • 311,858
  • 65
  • 665
  • 652
  • Good to see that someone else uses design patterns! Don't forget to implement the interface. – LastStar007 Jul 25 '12 at 17:59
  • Thanks for your post, quite helpful. I've updated my post with a clarification question regarding the final steps of your solution. – user640118 Jul 26 '12 at 19:24
  • @user640118: I don't quite understand your new requirement, isn't this enough: `FooOrBar fob = (condition true)? new FooAdapter(new Foo()) : new BarAdapter(new Bar())`? – Tomasz Nurkiewicz Jul 26 '12 at 19:30
  • That's it exactly, but I was concerned it wasn't good form to use if/else for assignment. Thanks! – user640118 Jul 26 '12 at 19:42
1

You could create a Tagged Class.

This is considered an anti-pattern, because they're inferior to using a class hierarchy, but since you don't have control over the hierarchy, you are left with little choice.

This gives you the benefit of knowing what to send over your webservice without resorting to instanceof.

class FooBar {
    public static enum Mode { FOO, BAR }
    Foo foo;
    Bar bar;
    Mode mode;
    FooBar(Foo foo) {
        mode = Mode.FOO;
        this.foo = foo;
    }
    FooBar(Bar bar) {
        mode = Mode.BAR;
        this.bar = bar;
    }

    public String getName() {
        switch(mode) {
            case FOO: foo.getName();
            case BAR: bar.getName();
            default: throw new IllegalStateException();
        }
    }

    public void setName(String name) {
        switch(mode) {
            case FOO: foo.setName(name); return;
            case BAR: bar.setName(name); return;
            default: throw new IllegalStateException();
        }
    }
    public Mode getMode() { return mode; }
}
corsiKa
  • 76,904
  • 22
  • 148
  • 194
1

Presumably you have no control over the generated classes (otherwise, it would be trivial!).

An alternative is to create a helper class and use reflection to set each and every property that you need to set (see How do I invoke a Java method when given the method name as a string?)

Community
  • 1
  • 1
hythlodayr
  • 2,367
  • 15
  • 23
  • You could, but reflection should be avoided where possible because it tends to complicate code. Upvote for creativity. – LastStar007 Jul 25 '12 at 18:05
  • Not only does it complicate code, but you lose compile time integrity. – corsiKa Jul 25 '12 at 18:07
  • All generally true, but would reflection be more complicated here? Regardless, I definitely agree losing compile-time checks is a major downside. – hythlodayr Jul 25 '12 at 18:42
0

I'm not exactly sure what your requirements are but have you considered the simplest solution of creating a wrapper class that holds an instance of foo and bar?

class FooOrBar {
    private Foo foo;
    private Bar bar;

    public setName(name) {
        if (foo != null) foo.name = name;
        if (bar != null) bar.name = name;
    }
}

You can add validations as needed to make sure only one item is referenced by a single wrapper.

Bort
  • 807
  • 6
  • 22