2

I have an Android app to assist in collecting data for animal observations. It has an activity ObserveAnimal and a model Animal with normal getters and setters.

I am creating a different flavor of the app with extended functionality and extended data for bird observations. ObserveBird extends ObserveAnimal and Bird extends Animal. ObserveBird adds some extra methods.

public class Animal {
    private String species;
    // there are more fields and public getters and setters ...
}

public class Bird extends Animal {
    private int wingLength;
    // public getters and setters ...
}

Problem is I can't find the right way to declare and initialize Bird. I tried several ways, like:

public class ObserveAnimal extends AppCompatActivity {
    protected Animal a = new Animal();
}

public class ObserveBird extends ObserveAnimal {
    protected Bird a = new Bird();
}

ObserveAnimal and Animal a work nicely together as they should.

However in ObserveBird theBird a declaration hides the Animal a declaration and I end up with two different instances. Instance Animal a gets its species field set from the code in ObserveAnimal and instance Bird a gets its wingLength field set from the code in ObserveBird.

I am trying to have one instance of Bird a in ObserveBird with species set from the code in ObserveAnimal and wingLength set from the code in ObserveBird.

I want to have an instance Bird a (and no other instance of Animal) when I start activity ObserveBird.

How can I do that without duplicating a lot of code from ObserveAnimal to ObserveBird?

Mario Huizinga
  • 780
  • 7
  • 14
  • Show how declarations of `Animal` and `Bird` looks like. – Marcin Orlowski Jan 31 '17 at 10:32
  • You can only **extend one class** in Java, but you can **implement several interfaces** if needed. [**See this link**](http://stackoverflow.com/questions/5836662/extending-from-two-classes) – Mistalis Jan 31 '17 at 10:32
  • An activity is not a model, do not try to treat it as such – Tim Jan 31 '17 at 10:42
  • @MarcinOrlowski I added Animal and Bird declarations. – Mario Huizinga Jan 31 '17 at 10:52
  • @TimCastelijns Activities and models are seperated. The activities have a lot more code like OnCreate(), a layout with views etcetera that I think is irrelevant for the question. The activities use the getters and setters of Animal and Bird. I added the model declarations to clarify the question. – Mario Huizinga Jan 31 '17 at 10:59
  • @Mistalis I think your link is for a different situation. See my updated question. – Mario Huizinga Jan 31 '17 at 11:44

2 Answers2

1

How can I do that without duplicating a lot of code from ObserveAnimal to ObserveBird?

You most likely would benefit from using abstract class and by logic Animal should be such class and Bird should just extend Animal. That way common code and logic stays with Animal

EDIT

I'd create interface both Animal and Birt must implement (i.e. AnimalContract) or have abstract base class for my models first:

public class Animal implements AnimalContract {
    private String species;
   // there are more fields and public getters and setters ...
}

public class Bird extends Animal {
    private int wingLength;
    // public getters and setters ...
}

And then, whenver I'd need any animal, be it bird, dog or whatever I'd want just AnimalContract, while still being able to requiring certain specie (i.e. Bird when explicitely needed).

Then I'd have base class for the observe thing:

abstract public class ObserveBase extends AppCompactActivity {
    abstract AnimalContract getModel();

    protected AnimalContract a;

    protected void init() {
        a = getModel();
    }

    ... all the common code here...

}

and have the init() called (or merged with i.e. onCreate()). Next I'd have my model returned by getModel() like that by subclasses:

public class ObserveAnimal extends ObserveBase {
    @Override
    public AnimalContract getModel() {
       return new Animal();
    }
}

and

public class ObserveBird extends ObserveBase {
    @Override
    public AnimalContract getModel() {
      return new Bird();
    }
}
Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
  • `Animal` can't be an abstract class, because `ObserveAnimal` requires an instance of `Animal`. – Mario Huizinga Jan 31 '17 at 11:04
  • Sure, that's fine actually and pretty normal too. But now I do not really understand what is your problem here. If Bird extends Animal then there should be no duplicated code if all is done right. What is problematic for you with the current `new Bird()` and `new Animal()` instantiation? – Marcin Orlowski Jan 31 '17 at 11:08
  • Thank you, very instructive and it works fine. I just had to add `Bird b = (Bird) a;` in `onCreate()` of activity `ObserveBird`, to get access to the methods of Bird like `setWingLength()`. – Mario Huizinga Jan 31 '17 at 17:10
  • Sure that's correct approach as you can **always** safely cast instance of `Bird` to `AnimalContract`. But you should be careful doing that other way as not all classes implementing `AnimalContract` are instance of`Bird`- only `Bird` itself and its subclasses. If you cast `Animal` you will face `ClassCastException`. Still, if you just need anything from base code, the it's best to cast to `AnimalContract` as you do not care it is `Bird` or `Dog` as this is irrelevant at that point. – Marcin Orlowski Jan 31 '17 at 17:40
-1

Something like

public class Observe<A extends Animal> extends AppCompatActivity {
    protected A a;
    public Observe(Class<A> clazz) {
        a = clazz.newInstance();
    }
}

And then call

Observe<Animal> animalActivity = new Observe<Animal>(Animal.class);
Observe<Bird> birdActivity = new Observe<Bird>(Bird.class);
Naetmul
  • 14,544
  • 8
  • 57
  • 81
  • That is an interesting approach. But as I understand it requires that I give up the separation of functionality in `ObserveAnimal` and `ObserveBird` activities and put it all into one activity `Observe`. In future I plan to add more flavors like observe Butterfly, Spider, Mammal and so on. It would be nice to have different activities as well as different models, both extending a base `ObserveAnimal` activity and a base `Animal` model. – Mario Huizinga Jan 31 '17 at 12:09