2

i am new in Java and i try to make some really simple java applications. In my attempts i have come to problem with generalisation. I have a list of Person objects. Person can be Father or Mother.

Then, i have couple of methods with same name eat(...) but they differ in input parameters. These methods are not part of Person class. One of these methods accepts Mother as parameter and the other accepts Father.

The question is how to dynamically decide which method to invoke on list of Person. when i try iterating through list and calling o.eat(iterator) it prompts with compiler error, because iterator is of type Person but my eat methods want Mother or Father as parameters. Compiler doesnt know that i have method for each type of Person

Thus far i have solved my problem with if statement in which i compare the class type by GetType() method with both Mother and Father and if it equals i can cast Person into appropriate type.

Code looks like this:

  if (person.getClass().equals(Father.class)) {
            theView.eat((Father) person);
        }


  if (person.getClass().equals(Mother.class)) {
            theView.eat((Mother) person);
        }

Eat method looks as follow:

 public void eat(Mother m){
    textArea.append(m.breakfast);
    textArea.append(m.lunch);
    textArea.append(m.dinner);
 }

lunch dinner and breakfast are just some string indicating what the person is doing

person is the code is iterator through list of Person objects

Is there any better solution which will automate the proccess?

Thx in advance.

Jenism
  • 107
  • 3
  • 9

3 Answers3

1

Use polymorphism:

public interface Person{
    void eat();
}

public class Mother implements Person{

    @Override
    public void eat()
    {
        //the code inside eat(Mother) goes here
    }

}

public class Father implements Person{

    @Override
    public void eat()
    {
        //the code inside eat(Father) goes here
    }

}

then, just call the eat method on each object of your Person's list:

for(final Person person: personList){
    person.eat();
}
Lucas Oliveira
  • 3,357
  • 1
  • 16
  • 20
  • thanks for answer, problem is that the eat method is not member of Person but the Person is argument of the method eat. Method eat is member of object that is responsible for the view of application. – Jenism Apr 29 '16 at 14:57
1

Then, i have couple of methods with same name eat(...) but they differ in input parameters

What if your class with different eat methods is implemented as follows:

public class TheView<T extends Person> {
    public void eat(T t) {
         textArea.append(t.getMeals());
    }
}

And now your iterating method can be implemented as follows:

public <T> void yourMethod(List<? extends Person> personList) {
    for (Person p : personList) {
         theView.eat(p);
    }
}

Your list can contain any number of Father or Mother objects provided they implement / extend Person class, as

public abstract class Person {
    private String breakfast;
    private String lunch;
    // ... other fields

    public abstract void getMeals();

    public String getBreakfast() { return breakfast; }
    // ... other getters
}

public class Father extends Person {
     @Override
     public void getMeals() {
         // implement Father-specific code here
     }
}

public class Mother extends Person {

     @Override
     public String getMeals() {
        StrngBuilder sb = new StringBuilder() ;

        sb.append(getBreakfast());
        sb.append(getLunch());
        sb.append(getDinner());

        return sb.toString();
    }
}
ujulu
  • 3,289
  • 2
  • 11
  • 14
  • but how can i tell if Mother or Father was passed to method eat(T t)? because i want to do different actions with Father than with Mother – Jenism Apr 29 '16 at 18:38
  • The `eat()` does not need to know which concrete type is passed in except it is of type `Person`. See the modified code above to get what I mean. – ujulu Apr 29 '16 at 19:13
  • but in this eat method, i want to append some text to a list box. so i cant do this in the model calsses of mother and father :( its a bit messy i know – Jenism Apr 29 '16 at 20:11
  • Can you post your `eat()` method so that I might help you? I am just guessing what you are doing in it. – ujulu Apr 29 '16 at 20:17
  • i have edited the code above, its that simple. lunch dinner and breakfast are just some string indicating what the person is doing, but suppose i dont want to display dinner for the father eat method – Jenism Apr 29 '16 at 20:25
  • I added a method (in this case `getMeals()`) that might give you an idea of what I am thinking. This is not the best solution because the `getMeals()` method might contain some duplicate code. But it might help you to remove the `if-else` checks. User @Brandon has given you the best answer (the visitor pattern) I think. – ujulu Apr 29 '16 at 21:24
  • thank you for your patience, i rly like this solution and yep it is getting closer and closer to the visitor and double dispatch pattern – Jenism Apr 29 '16 at 22:07
  • 1
    If you replace all the fields from the `Person` with `public enum Meal { BREAKFAST, LUNCH, DINNER; }` and change the `getMeals()` method accordingly, the code would be a bit cleaner. – ujulu Apr 30 '16 at 08:41
0

I think you need the Visitor pattern, because of what you said here

The question is how to dynamically decide which method to invoke on list of Person.

https://sourcemaking.com/design_patterns/visitor/java/2

This helps you decide which route to take dynamically at run time

From Wikipedia: https://en.wikipedia.org/wiki/Double_dispatch

double dispatch is a special form of multiple dispatch, and a mechanism that dispatches a function call to different concrete functions depending on the runtime types of two objects involved in the call.

Brandon Ling
  • 3,841
  • 6
  • 34
  • 49