Java - Best way to return multiple object types from a method [closed]
Asked Answered
B

4

9

In my DAO i have a method where i build 2 different objects and I want to return both of those objects, but i'm not sure what the best way is to do it. I've looked at using ? extends myObject, creating another class that holds both of my objects that i want to return, and just using List<Object>.

Long story short on why i need these similar objects is to display 1 on the screen and the other to use with primefaces dataexporter which doesn't handle lists in an object as far as i'm aware.

Class Person

public class Person() {
  firstName = null;
  lastName = null;
  List<Programs> programs = new ArrayList<Programs>();

  // Getters and setters
}

Class DataExporterPerson

public class DataExporterPerson() {
  firstName = null;
  lastName = null;
  String program = null;

  // Getters and setters
}

DAO method:

public List<SOMETHING> getPeople() {
  // query db for people

  // build both objects

  return ?????
}

Now i understand i can very easily create another object like the one below, but that seems like an inefficient way to do things because i'm basically creating an object just to return from 1 method.

public class PersonTransporter() {
  Person person = null;
  DataExporterPerson = null;
}

What is the best way to handle this scenario?

EDIT

The reason that i'm trying to return 2 objects in 1 method is because this is a DAO method that queries the database and builds 2 objects based on the data in the query. I don't want to break it up into 2 methods because i don't want to query the db twice if i don't need to.

Bayless answered 9/8, 2013 at 16:36 Comment(5)
Why does DataExporterPerson not extends Person? Then you could use a Collection<Person>.Saturnalia
I'll just link to this SO answer regarding lack of Pair in Java: #156775Nolin
It's generally a bad idea for a single method to do two things. Can you elucidate why the one method requires two return values?Stepaniestepbrother
It may not be doing do two things; it could do one thing and return a 2-tuple.Drivel
Question updated with reason for trying to return 2 objects in 1 method.Bayless
A
8

You can either handle this through inheritance, or containment.

You can have Person and DataExporterPerson extend something like AbstractPerson. However, since you have not already done so, then it is probably inappropriate to do inheritance.

I think it was Effective C++ that talked about how containment is better than inheritance. IIRC the reason stated is that containment is more loosely coupled than inheritance.

Here you would have a object that contains both Person and DataExporterPerson. Your method would populate one of those for this union type object, and by seeing which one is null you would know which one you actually have.

public class DBPersonUnion {
  private Person person = null;
  private DataExporterPerson dataExporterPerson = null;

  //getters and setters.
}
Allhallowtide answered 9/8, 2013 at 16:41 Comment(2)
Tack on one or two helper methods or an enumeration for these 'union' types with more than a few possible options. It's effectively a loose Algebraic Data Type.Drivel
Even if i have Person and DataExporterPerson extend AbstractPerson, how would that help me because I would still need to return both Person and DataExporterPerson from my DAO method.Bayless
A
5

If your method need to return two different types this is a hint that there is something wrong with your architecture or method logic.

What you can do ?

  • Create a class that will logically join the elements,
  • Introduce common interface that, both class will implement,
  • Implement two methods fist return with object, that second use a parameter and return the second object.

The example for last point

 class Foo {
    String f;
 } 

 class Bar {
   String b;
 }

Then problem how to return object Foo and Bar ?

 public Object theProblemMethod() {

      Foo a = new Foo();
          a.foo = "Test";

      Bar b = new Bar();
          b.bar = a.foo;   //The logic where class Foo meet class Bar.

    return ???

 }

The valid implementation

   public Foo createFoo(){ 
      Foo a = new Foo();
          a.foo = "Test";
      return a;
   } 

   public Bar createBar(Foo f) {

      Bar b = new Bar();
          b.bar = f.foo; 
      reutrn b;
   }

Usage

   public void action()  {

           //theProblemMethod(); //This we can not do

          Foo a = createFoo();
          Bar b = createBar(a);
  }
Aquitaine answered 9/8, 2013 at 16:45 Comment(2)
can you please edit your III'rd point.It is not clear.Oberg
@Algorithmist, I hope that now i clear.Ciapas
S
2

Your actual issue here is one of design. No method should be doing more than one thing: therefore a method that returns two unlike objects is probably bad design. To actually solve this problem, you should break your method into two, separate methods to handle the two different concerns.

However, let us assume you cannot do this. Based on your notes it seems most of your state in the two objects is repeated. You can combine these two by having them inherit from a similar source - but this only solves half your problem. Instead, you can decorate the one with the other:

public class DataExporterPerson {
  private Person person;
  private String program = null; //or any other

  //other getters/setters, esp to get the core 'person' object.
  //note that getters/setters for repeated state should just
  //  pass through to the underlying object:
  public String getName() { person.getName(); } //for example
}

If you absolutely must return two objects, you may do this, but it's hard to test and violates the 'no side effect' principle:

public boolean buildThings(ThingA a, ThingB b) {
  a = <whatever>;
  b = <whatever else>;

  return true;//success!
}

//...
//somewhere else in code
ThingA a = null;
ThingB b = null;
boolean result = buildThings(a, b);
//use a and b here
Stepaniestepbrother answered 9/8, 2013 at 16:52 Comment(4)
Your second example won't work because my objects are in a different class. My ThingA and ThingB are in my backing bean, and my method is in my DAO.Bayless
Then you're asking a different question altogether from 'how do I return two objects from one method?'.Stepaniestepbrother
Not really. I have classA.methodA calling ClassB.methodA, which i am trying to return multiple objects from ClassB.method.Bayless
Ok, then the first part will probably handle what you need. Your question, though, is violently unclear: and that is a good sign your design is waaay off. I don't think you ever really want to return two objects. There are simply better alternatives. In this case you want decoration.Stepaniestepbrother
L
-2

You could do two different things.

The first have the method signature be public List<Object> getPeople(). This will allow you to do instanceof and figure out which is which.

OR

you could have DataExporterPerson extend Person (or make a new class/interface that both DataExporterPerson and Person extend/implements and use that as the type).

Lictor answered 9/8, 2013 at 16:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.