2

I have two classes: Fish and Plant. They do not inherit from any classes.

But both of them have one method called isAlive() which have the same implementation details. Now I have a list of fish and another list of dog and I need to remove dead fish and dead dog. I want my method to have same name but it is not possible without adding additional field to method signature. Is it possible I do not need to write additional chunk of code which does the same as the last chunk of code?

Below is the code. For class Model, Fish and Plant are two data members and they are ArrayList of Fish and Plant objects.

Is there any way I can write only one method called count and I do not need to add additional field to my method signature or modify my return type?

public class Fish{
    public boolean isAlive(){
        if(this.size > 0){
            return true;
        }
        return false;
    }
}
public class Plant{
    public boolean isAlive(){
        if(this.size > 0){
            return true;
        }
        return false;
    }
}

public class Model{
    private int countDeadFish() {
        int totalCount = 0;
        for(Fish aFish : this.fish) {
            if(aFish.isAlive() == false) {
                totalCount += 1;
            }
        }
        return totalCount;
    }

    private int countDeadPlants() {
        int totalCount = 0;
        for(Plant plant : this.plants) {
            if(plant.isAlive() == false) {
                totalCount += 1;
            }
        }
        return totalCount;
    }
}
3
  • 1
    You should use a super-class for both Fish and Plant classes because the method isAlive() is the same and let them extends it. And for your Model class you just need one of these methods which operates on the super-class or takes params. Commented May 6, 2018 at 8:01
  • tutorialsandyou.com/java/inheritance-in-java-13.html check this first Commented May 6, 2018 at 8:06
  • Note if(this.size > 0) { return true; } return false; can be replaced by return size > 0 and if(plant.isAlive() == false) can be replaced by if(!plant.isAlive()). And totalCount += 1; can be replaced by totalCount++. This code is somewhat ... nasty. Commented May 6, 2018 at 8:30

5 Answers 5

2

If you do not want to use inheritance, then you can use a common method:

public class AliveChecker {

    public static boolean isAlive(int size) {
        return size > 0;
    }

}

public class Plant{
    public boolean isAlive(){
        return AliveChecker.isAlive(this.size);
    }
}

public class Fish{
    public boolean isAlive(){
        return AliveChecker.isAlive(this.size);
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

+ for link and answer too
1

Since Fishand Plant do not inherit from anything yet you can consider creating a superclass and extend from it:

public class LivingThing {
    protected int size = 1;
    public boolean isAlive() {
        return size > 0;
    }
}

public class Plant extends LivingThing {
}

public class Fish extends LivingThing {  
}

This example uses inheritance to classify Plantand Fish into the superclass LivingThing. You can set the size for example in the constructor of the Plant or an instance method:

public class Plant extends LivingThing {
    public Plant(int size){
        this.size = size;
    }
}

Your Model could then be:

public class Model{
    private int countDeadFish() {
        return countDead(this.fish);
    }

    private int countDeadPlants() {
        return countDead(this.plants);
    }

    private int countDead(ArrayList<LivingThing> things) {
        int totalCount = 0;
        for(LivingThing thing: things) {
            if(!thing.isAlive()) {
                totalCount++;
            }
        }
        return totalCount;
    }
}

Comments

0

Use interface

public interface LiveObject {
    boolean isAlive();
}

public class Fish implements LiveObject {
    public boolean isAlive(){
        if(this.size > 0){
            return true;
        }
        return false;
    }
}

public class Plant implements LiveObject {
    public boolean isAlive(){
        if(this.size > 0){
            return true;
        }
        return false;
    }
}

public class Model{

    private int countDead(Collection<LiveObject> objects) {
        int totalCount = 0;
        for(LiveObject obj : objects) {
            if(obj.isAlive() == false) {
                totalCount += 1;
            }
        }
        return totalCount;
    }

    private int countDeadFish() {
        return countDead(this.fish);
    }
}

Comments

0

Based on the comments it seems you can't modify Fish or Plant. Here's an approach to reduce duplication in countDead<Something> methods which does not require this.

Basically you want to count items in an array which satisfy certain criteria. With Java 8 you can capture this criteria in a predicate using lambdas or method references. You do not need inheritance or implementation of a certain interface for this.

private long countDeadFish() {
    return countDeadItems(this.fish, Fish::isAlive);
}

private long countDeadPlants() {
    return countDeadItems(this.plants, Plant::isAlive);
}

private <T> long countDeadItems(Collection<T> items, Predicate<? super T> isAlive) {
    return items.stream().filter(isAlive.negate()).count();
}

Comments

0

You could create a utility method (in a utility class somewhere):

public final class Liveliness {

    private Liveliness() {
    }

    public static boolean isAlive(final IntSupplier sizer) {
        return sizer.getAsInt() > 0;
    }

}

Your method then becomes:

public boolean isAlive(){
    return Liveliness.isAlive(this::getSize);
}

Alternatively, use an interface Life:

public interface Life {

    int getSize();

    default boolean isAlive(){
        return getSize() > 0;
    }
}

This way, adding a getSize method and inheriting from Life will add the method.


Note, avoid the following antipattern:

if(test) {
    return true;
} else {
    return false;
}

Use return test.

1 Comment

It can be called whatever you want to call it - it is "a utility class somewhere".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.